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

Naw*_*waz 6 c++ wcf multithreading web-services

背景:

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

问题:

我面临的问题是所有其他线程正常退出,除了工作线程,你可以看到自己,在下图中WorkerThreadProc没有使用CPU周期但它没有退出.还有很少其他线程在运行,这些线程不是由我创建的,而是由运行时创建的.

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

  • WorkerThreadProc处于Wait:WrUserRequest状态.
  • wWinMainCRTStartup处于Wait:UserRequest状态.
  • 所有TpCallbackIndependent都在等待:WrQueue状态.

他们在等什么?有什么可能导致我需要研究?另外,WrUserRequestUserRequest有什么区别WrQueue是什么意思?我完全不知道这里发生了什么.

在此输入图像描述


这是我的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;
}
Run Code Online (Sandbox Code Playgroud)

请看T_VERBOSE宏,它用于记录详细消息.我看到消息被记录,但线程没有退出!


编辑:

我只是评论了我的以下行WorkerThreadProc,然后工作线程优雅地退出!

SendMessage(pGuiData->m_hWnd, WM_CLOSE, 0, 0);
Run Code Online (Sandbox Code Playgroud)

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

Nec*_*lis 3

如果我们查看 的文档SendMessage,您可以看到这个小引用:

要发送消息并立即返回,请使用 SendMessageCallback 或 SendNotifyMessage 函数。要将消息发布到线程的消息队列并立即返回,请使用 PostMessage 或 PostThreadMessage 函数。

和这个:

仅当接收线程执行消息检索代码时,才会处理线程之间发送的消息。发送线程被阻塞,直到接收线程处理消息。但是,发送线程将在等待其消息被处理的同时处理传入的非排队消息。为了防止这种情况,请使用 SendMessageTimeout 并设置 SMTO_BLOCK。有关非排队消息的更多信息,请参阅非排队消息。

因此,从这里我们可以看到SendMessage,将阻塞直到消息被处理,这可能会以某种方式导致代码中的死锁,因为 msgproc 并不驻留在您的工作线程中,从而导致上下文切换(仅当线程的队列被泵送消息)。尝试使用PostMessage,它会立即返回。

编辑:这里还有一个关于消息死锁的不错的小信息SendMessage