为啥win32线程不自动退出?
Posted
技术标签:
【中文标题】为啥win32线程不自动退出?【英文标题】:Why win32 thread doesn't exit automatically?为什么win32线程不自动退出? 【发布时间】:2012-02-10 11:33:02 【问题描述】:背景:
在我用 C++ 编写的应用程序中,我创建了一个工作线程,该工作线程又使用 CreateThread()
创建了两个线程。工作线程创建的两个线程通过客户端与 WCF 服务通信,该客户端使用 Windows Web Services API 实现,该客户端提供 C/C++ 应用程序编程接口 (API),用于构建基于 SOAP 的 Web 服务和客户端。我的应用程序仅使用此 API 实现客户端。
问题:
我面临的问题是所有其他线程都正常退出,除了工作线程,正如您自己看到的那样,在下图中WorkerThreadProc
不使用 CPU 周期但它没有退出。还有一些其他线程不是我创建的,而是运行时创建的。
线程状态如下(ProcessExplorer报道):
WorkerThreadProc
处于 Wait:WrUserRequest 状态。
wWinMainCRTStartup
处于 Wait:UserRequest 状态。
所有TpCallbackIndependent
都处于Wait: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
是罪魁祸首?为什么会阻塞调用线程?
【问题讨论】:
你是在线程句柄退出后调用 CloseHandle() 吗?您应该使用 WaitForSingleObject() 来等待线程完成。 @infact:当然,是的!是的,我正在使用WaitForSingleObject
等待线程完成!
你为什么不使用像 boost::thread
这样被证明可以正常工作(甚至是可移植的)的抽象?
@PlasmaHH:我不需要便携性。另外,你的意思是win32线程不好(事实证明是这样)? boost::thread
内部使用什么?
@PlasmaHH:如果我提出有关boost::thread
的问题怎么办?我觉得你的论点很弱。
【参考方案1】:
如果我们查看SendMessage
的文档,您会看到这个小引语:
要发送消息并立即返回,请使用 SendMessageCallback 或 SendNotifyMessage 函数。将消息发布到线程的消息 排队并立即返回,使用 PostMessage 或 PostThreadMessage 功能。
还有这个:
线程之间发送的消息只有在接收时才被处理 线程执行消息检索代码。发送线程被阻塞 直到接收线程处理消息。然而,发送 线程将在等待它的同时处理传入的非排队消息 要处理的消息。为防止这种情况,请将 SendMessageTimeout 与 SMTO_BLOCK 设置。有关非排队消息的更多信息,请参阅 非排队消息。
所以从这里我们可以看到SendMessage
将阻塞直到消息被处理,这可能会导致代码中的死锁,因为 msgproc 不驻留在您的工作线程中,从而导致上下文切换(仅当线程的队列被抽出消息时触发)。尝试使用PostMessage
,它会立即返回。
编辑:here 也有关于来自SendMessage
的消息死锁的一小段信息
【讨论】:
在我自己发现了SendMessage()
的问题后(正如我在我的问题中发布的那样),我阅读了 MSDN 上的文档(您已将其发布为答案),但我不是得到这就是为什么SendMessage
没有返回。它不返回意味着接收线程不处理消息,这反过来意味着如果我使用PostMessage
,那么即使那样它也不会处理消息。虽然,它会解决阻塞线程的问题,但真正的问题(我们现在知道)仍然存在,那就是:消息没有被处理!
@Nawaz:使用 Spy++ 之类的东西会更好地解决这部分问题,我也遇到了类似的问题,WM_CLOSE
消息未被处理,将其追溯到另一个返回错误值的窗口消息,导致将WM_CLOSE
消息从队列中删除,因此无法处理以上是关于为啥win32线程不自动退出?的主要内容,如果未能解决你的问题,请参考以下文章