背景
在我用C ++编写的应用程序中,我创建了一个工作线程,后者又使用CreateThread()
创建了两个线程。工作线程创建的两个线程通过客户端与WCF服务进行通信,该客户端使用Windows Web Services API实现,该客户端提供用于构建基于SOAP的Web服务和客户端的C / C ++应用程序编程接口(API)。我的应用程序使用此API实现仅客户端。
问题:
我面临的问题是所有其他线程正常退出,除了工作线程,你可以看到自己,在下图中WorkerThreadProc
没有使用CPU周期但它没有退出。还有一些其他线程在运行,这些线程不是由我创建的,而是由运行时创建的。
线程状态如下(由ProcessExplorer报告):
WorkerThreadProc
位于等待:WrUserRequest 状态。wWinMainCRTStartup
位于等待:UserRequest 状态。TpCallbackIndependent
都在等待:WrQueue 状态。他们还在等什么?有什么可能导致我需要研究?另外, WrUserRequest 和 UserRequest 之间有什么区别? 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;
}
请参阅T_VERBOSE
宏,它用于记录详细消息。我看到消息被记录,但线程没有退出!
编辑:
我刚评论了WorkerThreadProc
中的以下行,然后工作线程正常退出!
SendMessage(pGuiData->m_hWnd, WM_CLOSE, 0, 0);
这是否意味着SendMessage
是罪魁祸首?为什么它会阻塞调用线程的线程?
答案 0 :(得分:3)
如果我们查看SendMessage
的文档,您可以看到这个小小的引用:
要发送消息并立即返回,请使用SendMessageCallback 或SendNotifyMessage函数。将消息发布到线程的消息 队列并立即返回,使用PostMessage或PostThreadMessage 功能
和此:
线程之间发送的消息仅在接收时处理 线程执行消息检索代码。发送线程被阻止 直到接收线程处理消息。但是,发送 线程将在等待它时处理传入的非排队消息 要处理的消息。要防止这种情况,请使用SendMessageTimeout SMTO_BLOCK设置。有关非排队消息的更多信息,请参阅 非排队消息。
因此我们可以看到SendMessage
将阻塞直到消息被处理,这可能会以某种方式导致代码死锁,因为msgproc不驻留在您的工作线程中,导致上下文切换(只有在为消息提取线程的队列时才会触发)。尝试使用PostMessage
,它会立即返回。
SendMessage
的消息死锁还有一小段信息here