2012-02-10 5 views
6

фон:Почему win32 поток не выходит автоматически?

В моем приложении, написанном в C++, я создаю рабочий поток, который, в свою очередь создает два потока с помощью CreateThread(). Два потока, которые создает рабочий поток, общаются с WCF-службой через клиента, который реализован с использованием Windows Web Services API, который предлагает интерфейс программирования приложений C/C++ (API) для создания веб-сервисов и клиентов на основе SOAP. Мое приложение реализует только только клиентом, использующим этот API.

Проблема:

Проблема я столкнулся в том, что все остальные потоки выхода из грациозно, кроме рабочего потока, как вы можете видеть себя в изображении ниже, что WorkerThreadProc не использует циклов центрального процессора пока он Безразлично Выход. Есть также несколько других потоков, которые не созданы мной, а временем выполнения.

нить состояния следующим образом (по данным ProcessExplorer):

  • WorkerThreadProc в Wait: WrUserRequest состояние.
  • wWinMainCRTStartup находится в Подождите: UserRequest состояние.
  • Все TpCallbackIndependent находятся в Подождите: WrQueue состояние.

Что они ожидают? Какие могут быть возможные причины, по которым мне нужно заглянуть? Кроме того, в чем разница между WrUserRequest и UserRequest? А что означает WrQueue? Я абсолютно не знаю, что здесь происходит.

enter image description here


Вот мой WorkerThreadProc код. Я удалил все операторы лесозаготовительных за исключением последнего в нижней части функции:

DWORD WINAPI WorkerThreadProc(PVOID pVoid) 
{ 

    //Initialize GDI+ 
    GdiplusStartupInput gdiplusStartupInput; 
    ULONG_PTR   gdiplusToken; 

    Status status = GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); 
    if (status != Status::Ok) 
    { 
     return 1; 
    } 

    GuiThreadData *pGuiData = (GuiThreadData*)pVoid; 

    auto patternIdRequestQueue= new PatternIdRequestQueue(); 
    auto resultQueue = new ResultQueue(); 

    auto patternManager = new PatternManager(patternIdRequestQueue); 
    LocalScheduler *pScheduler = new LocalScheduler(resultQueue, patternManager); 

    bool bInitializationDone = pScheduler->Initialize(pGuiData->m_lpCmdLine); 
    if (!bInitializationDone) 
    { 
     return 0; 
    } 

    //PatternIdThread 
    PatternIdThread patternIdThread(patternIdRequestQueue); 
    DWORD dwPatternIdThreadId; 
    HANDLE hPatternIdThread = CreateThread(NULL, 0, PatternIdThreadProc, &patternIdThread, 0, &dwPatternIdThreadId); 

    ResultPersistence resultPersistence(resultQueue); 
    DWORD dwResultPersistenceThreadId; 
    HANDLE hResultPersistenceThread = CreateThread(NULL, 0, ResultPersistenceThreadProc, &resultPersistence, 0, &dwResultPersistenceThreadId); 

    pScheduler->ScheduleWork(pGuiData->m_hWnd, pGuiData->m_hInstance, ss.str()); 

    pScheduler->WaitTillDone(); 
    patternIdThread.Close(); 
    resultPersistence.Close(); 

    delete pScheduler; 

    //Uninitialize GDI+ 
    GdiplusShutdown(gdiplusToken); 

    dwRet = WaitForSingleObject(hPatternIdThread, INFINITE); 
    CloseHandle(hPatternIdThread); 

    dwRet = WaitForSingleObject(hResultPersistenceThread,INFINITE); 
    CloseHandle(hResultPersistenceThread); 

    SendMessage(pGuiData->m_hWnd, WM_CLOSE, 0, 0); 

    //IMPORTANT : this verbose message is getting logged! 
    T_VERBOSE(EvtSrcInsightAnalysis, 0, 0, "After sending message to destroy window"); 

    delete patternManager; 
    delete patternIdRequestQueue; 
    delete resultQueue; 
    return 0; 
} 

Пожалуйста, смотрите T_VERBOSE макросъемки используется для входа подробного сообщения. Я вижу, что сообщение регистрируется, но поток не выходит!


EDIT:

Я просто заметил следующую строку по моему WorkerThreadProc, то рабочий поток выходит изящно!

SendMessage(pGuiData->m_hWnd, WM_CLOSE, 0, 0); 

Означает ли это, что SendMessage является виновником? Почему он блокирует поток вызывающим потоком?

+0

Вы звоните CloseHandle() на ручке потока после его выхода? Вы должны использовать WaitForSingleObject(), чтобы дождаться окончания потока. –

+0

@ infact: Конечно, да! И да, я использую 'WaitForSingleObject', чтобы дождаться окончания потока! – Nawaz

+0

Почему бы вам не использовать абстракции, такие как 'boost :: thread', которые, как доказано, работают нормально (и даже переносимы)? – PlasmaHH

ответ

3

Если мы посмотрим на документы для SendMessage, вы можете увидеть эту маленькую цитату:

Чтобы отправить сообщение и вернуться немедленно, используйте функцию SendMessageCallback или SendNotifyMessage. Чтобы отправить сообщение в сообщение потока и немедленно вернуть его, используйте функцию PostMessage или PostThreadMessage .

и это:

Сообщения, передаваемые между потоками обрабатываются только тогда, когда принимающий поток выполняет код извлечения сообщения. Посылающий поток блокируется до тех пор, пока принимающий поток не обработает сообщение. Тем не менее, отправляющий поток будет обрабатывать входящие незарезервированные сообщения в ожидании обработки его сообщения . Чтобы предотвратить это, используйте SendMessageTimeout с SMTO_BLOCK. Дополнительные сведения о незарегистрированных сообщениях см. В разделе Непредусмотренные сообщения.

так из этого мы можем видеть SendMessage перекроют до сообщений обрабатываются, что может какой-то образом привести к тупиковой ситуации в вашем коде, как msgproc не находится в вашем рабочем потоке, что приводит к смене контекста (который запускается только тогда, когда очередь потока загружается для сообщений). Попробуйте использовать PostMessage, который немедленно возвращается.

EDIT: есть также хороший маленький кусочек информации here на тупики сообщения от SendMessage

+0

После выяснения проблемы с 'SendMessage()' self (поскольку я опубликовал это в своем вопросе), я прочитал документ (который вы отправили как ответ) в MSDN, но то, что я не получаю, SendMessage' не возвращается. Он не возвращает, что получающий поток не обрабатывает сообщения, что по очереди подразумевает, что если я использую 'PostMessage', тогда он не будет обрабатывать сообщения даже тогда. Хотя, это решит проблему блокировки потока, но реальная проблема (которую мы * теперь знаем) все еще существует, а именно: сообщения не обрабатываются! – Nawaz

+0

@Nawaz: эта часть была бы лучше решена с использованием чего-то вроде Spy ++. Я также столкнулся с аналогичной проблемой с сообщениями 'WM_CLOSE', которые не обрабатываются, отследили его обратно в другое сообщение окна, возвращая неправильное значение, что приводит к сообщению' WM_CLOSE' удалено из очереди, чтобы оно не могло быть обработано – Necrolis

Смежные вопросы