2015-05-12 3 views
7

Некоторые предпосылки: Я пытаюсь отслеживать ошибку, которая вызывает у меня серьезные головные боли. После многих тупиков (см this question) я, наконец, в конечном итоге с этим кодом:Программа зависает в отладчике Visual Studio

#include <thread> 
#include <vector> 
#include <iosfwd> 
#include <sstream> 
#include <string> 
#include <windows.h> 

int main() 
{ 
    SRWLOCK srwl; 
    InitializeSRWLock(&srwl); 
    for(size_t i=0;i<1000;++i) 
    { 
     std::vector<std::thread>threads; 
     for(size_t j=0;j<100;++j) 
     { 
      OutputDebugString("."); 
      threads.emplace_back([&](){ 
       AcquireSRWLockExclusive(&srwl); 
       //Code below modifies the probability to see the bug. 
       std::this_thread::sleep_for(std::chrono::microseconds(1)); 
       std::wstringstream wss; 
       wss<<std::this_thread::get_id(); 
       wss.str(); 
       //Code above modifies the probability to see the bug. 
       ReleaseSRWLockExclusive(&srwl);}); 
     } 
     for(auto&t:threads){t.join();} 
     OutputDebugString((std::to_string(i)+"\n").data()); 
    } 
    return 0; 
} 

Когда я запускаю этот код в VS 2013 отладчика программа свисает с выходом, как этот:

....................................................................................................0 
....................................................................................................1 
....................................................................................................2 
........................... 

странно достаточно. Если я приостанавливаю отладчик и проверяю, что происходит, один из потоков находится внутри AcquireSRWLockExclusive (в NtWaitForAlertByThreadId), по-видимому, нет причин, по которым программа висит. Когда я нажимаю кнопку «возобновить», программа с радостью продолжает и печатает еще несколько вещей, пока она не будет заблокирована снова.

У вас есть идея, что здесь происходит?

Некоторые подробнее:

  • Насколько я могу судить, это ошибка существует только на Windows, 8.1.
  • Я пробовал VS2013.4 и VS2015 RC.
  • Я могу воспроизвести его на двух разных компьютерах под Windows 8.1.
  • Один из машины был отформатирован, ОЗУ, процессор и диск испытания (я подумал о неисправности, потому что сначала я мог только наблюдать ошибку на этой конкретной машине)
  • Я никогда не мог воспроизвести его на Windows 7.
  • Может быть полезно изменить код между комментариями для наблюдения за ошибкой. Когда я добавил микросекундный сон, я мог наконец воспроизвести ошибку на другом компьютере.
  • С VS2015 RC я мог бы воспроизвести одно и то же поведение с простым std :: mutex. Однако на VS2013 SRWLOCK кажется обязательным для наблюдения за ошибкой.
+0

Возможно, вы находитесь в тупике, и как только вы входите в отладчик, он меняет синхронизацию, и тупик исчезает. – NathanOliver

+0

@NathanOliver Как это возможно? В коде есть только один мьютекс. – Arnaud

+0

Запускает ли программа когда-либо за пределами отладчика? –

ответ

4

Эта проблема вызвана ошибкой планировщика ОС, представленной в обновлении весной 2014 года до Windows 8.1. Исправление для этой проблемы было выпущено в мае 2015 года и доступно по адресу https://support.microsoft.com/en-us/kb/3036169.

+0

Я испробовал исправление, и оно решает проблему. Это кажется намного более медленным, хотя. – Arnaud

1

Для меня это похоже на ошибку в ОС Windows, у меня есть разные варианты кода, которые зависают с использованием новых примитивов Vista под отладчиком в Win 8.1/Server 2012R2 после апрельского обновления 2014 года. Также висит также функция ожидания пула потоков. Похоже, он в основном привязан к завершенному исполнению другого потока в момент ожидания/блокировки. Вот простой код, который всегда висит под отладчиком NtWaitForAlertByThreadId():

#include <windows.h> 

#include <stdio.h> 
#include <conio.h> 
#include <tchar.h> 

#pragma optimize("",off) 
VOID CALLBACK _WorkCallback(PTP_CALLBACK_INSTANCE Instance, PVOID pUser, PTP_WORK Work) 
{ 
    for (int i = 0; i < INT_MAX/256; i++) {} 
} 

DWORD WINAPI ThreadProc(LPVOID lpParameter) 
{ 
    for (int i = 0; i < INT_MAX/256; i++) {} 
    return 0; 
} 
#pragma optimize("",on) 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    LONGLONG c = 0; 

    while(!_kbhit()) 
    { 
     PTP_WORK ptpw = CreateThreadpoolWork(&_WorkCallback, NULL, NULL); 
     if (ptpw != NULL) 
     { 
      for(long i = 0; i < 3; i++) SubmitThreadpoolWork(ptpw); 

      CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL); 

      WaitForThreadpoolWorkCallbacks(ptpw, FALSE); 
      CloseThreadpoolWork(ptpw); 
     } 

     printf("%I64d         \r", c++); 
    } 

    _getch(); 
    return 0; 
} 

К сожалению, я понятия не имею, куда сообщить об этом в Microsoft.

+0

Я мог бы воспроизвести висящую на моей системе тоже. – Arnaud