为什么Win32线程不会自动退出?

6

背景:

我的C++应用程序创建了一个工作线程,该线程使用CreateThread()创建了两个线程。工作线程创建的这两个线程通过客户端与WCF服务通信,该客户端使用Windows Web Services API实现,该API提供了用于构建基于SOAP的Web服务和客户端的C/C++应用程序编程接口(API)。我的应用程序仅使用此API实现了客户端。

问题:

我面临的问题是,除了工作线程外,所有其他线程都会优雅地退出,正如您自己在下面的图像中所看到的那样,WorkerThreadProc不使用CPU周期,但它不会退出。还有一些其他正在运行的线程,它们不是由我创建的,而是由运行时创建的。

线程状态如下(由ProcessExplorer报告):

  • WorkerThreadProc处于Wait:WrUserRequest状态。
  • wWinMainCRTStartup处于Wait:UserRequest状态。
  • 所有TpCallbackIndependent都处于Wait:WrQueue状态。

他们在等什么?我需要查看哪些可能的原因?WrUserRequestUserRequest之间有什么区别?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宏,它用于记录详细信息。我发现消息已经被记录了,但线程没有退出!编辑:我只是在WorkerThreadProc中注释了以下行,然后工作线程正常退出!
SendMessage(pGuiData->m_hWnd, WM_CLOSE, 0, 0);

这是否意味着 SendMessage 是罪魁祸首?为什么会阻塞调用线程?

当然,是的!而且,我正在使用WaitForSingleObject等待线程完成! - Nawaz
@PlasmaHH:我不需要可移植性。另外,你是说win32线程很糟糕(并已被证明如此)吗?boost::thread在内部使用什么? - Nawaz
1
@PlasmaHH:如果我提出关于boost::thread的问题,你觉得怎么样?我认为你的论点不够有力。 - Nawaz
@AmigableClarkKant:我应该添加什么作为答案? - Nawaz
我刚刚在我的WorkerThreadProc中注释了以下行,然后工作线程优雅地退出了! - Prof. Falken
显示剩余14条评论
1个回答

3
如果我们查看SendMessage的文档,你会看到这段引用:
“使用SendMessageCallback或SendNotifyMessage函数发送消息并立即返回。使用PostMessage或PostThreadMessage函数将消息发布到线程的消息队列并立即返回。”
还有这个:
“在线程之间发送的消息仅在接收线程执行消息检索代码时处理。发送线程被阻塞,直到接收线程处理消息。但是,在等待其消息被处理时,发送线程将处理传入的非排队消息。为了防止这种情况,请使用带有SMTO_BLOCK设置的SendMessageTimeout。有关非排队消息的更多信息,请参见非排队消息。”
因此,从中我们可以看出,SendMessage将一直阻塞,直到消息被处理,这可能会导致您的代码死锁,因为msgproc不驻留在您的工作线程中,导致上下文切换(只有在线程的队列中抽取消息时才触发)。尝试使用PostMessage,它会立即返回。
编辑:这里还有一个关于SendMessage消息死锁的好消息here

在我自己找出SendMessage()的问题后(正如我在我的问题中发布的),我阅读了MSDN上您发布的答案,但我不明白的是为什么SendMessage没有返回。它不返回意味着接收线程不处理消息,这反过来又意味着即使我使用PostMessage,它也不会处理消息。虽然,它将解决阻塞线程的问题,但真正的问题(我们现在知道)仍然存在,那就是:消息没有被处理! - Nawaz
@Nawaz:那部分最好使用类似Spy++的工具来解决,我也遇到过类似的问题,即WM_CLOSE消息未被处理,将其追溯到另一个窗口消息返回了错误的值,导致WM_CLOSE消息从队列中删除,因此无法被处理。 - Necrolis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接