等到消息循环在另一个线程上时窗口关闭
Posted
技术标签:
【中文标题】等到消息循环在另一个线程上时窗口关闭【英文标题】:Wait until window closes when message loop is on another thread 【发布时间】:2011-07-29 20:01:18 【问题描述】:在一个 C++ 应用程序中,我有一个窗口,其消息循环在单独的线程中运行,因为主线程正忙于计算和渲染模拟。该窗口充当模拟的日志窗口。当模拟抛出异常时,模拟关闭,日志窗口显示详细信息。
现在主线程应该等到日志窗口关闭。由于消息循环在单独的线程上运行,因此我尝试了
WaitForSingleObject(logwindow->thread, INFINITE);
来自主线程。
但是,这似乎阻止了消息泵并且日志窗口冻结。那么如何正确等待窗口关闭或线程结束呢?
ED:窗口是在主线程上创建的,但在不同的线程上运行。我将继续进行更改,以便它也在消息循环线程上创建。
【问题讨论】:
窗口最初是在哪个线程中创建的? windows 不应在 WinAPI 中的线程之间迁移 好的,我会确保它也在循环线程上创建。INFINITE
就是您所期望的。如果您从未向该线程发出信号,它将永远等待。添加代码以指示线程继续或指定超时值而不是INFINITE
。附言您可以在处理 WM_CLOSE 时向您的另一个窗口发送自定义消息,让他知道它而不是阻止并加入线程。
如果您在主线程上创建它,那么它的所有消息也将由主线程泵送!
这对我来说是新的,谢谢!
【参考方案1】:
你有几个选择。
-
在主线程之外运行所有 UI,并让工作线程将报告同步回主线程以显示,例如通过
PostMessage
或SendMessage
。
不要等待,让工作线程在工作完成后向主线程发布消息。
请使用MsgWaitForMultipleObjects
等待。
详细说明MsgWaitForMultipleObjects
,它是一个等待函数,可以配置为在消息到达队列时返回。因此,您可以保持消息泵处于活动状态,同时在处理排队消息之间使用阻塞等待。
在伪代码中你可以这样写:
do
WaitResult = MsgWaitForMultipleObjects(1, hThread, TRUE, INFINITE, QS_ALLEVENTS);
if (WaitResult == MessageArrivedOnQueue)
PumpMessageQueue();
while (WaitResult != WaitHandlesSignaled)
【讨论】:
3.将需要对代码进行最少的更改,我会先尝试。 选项 3 可能是最简单的,但选项 1 是我的建议。 在设计方面,1. 会更好。我会选择那个。【参考方案2】:日志窗口在主线程处于阻塞等待时冻结的事实表明工作线程正在向主线程发送消息然后等待回复,但主线程已经被阻塞并且无法回复它。这是两个线程的典型死锁情况。您应该在主线程中使用MsgWaitForMultipleObjects()
而不是WaitForSingleObject()
来检测新消息何时需要在等待时进行处理,例如:
do
DWORD dwRet = MsgWaitForMultipleObjects(1, &(logwindow->thread), FALSE, INFINITE, QS_ALLINPUT);
if (dwRet == 0xFFFFFFFF) break;
if (dwRet == (WAIT_OBJECT_0 + 1))
process messages here...
while (dwRet != WAIT_OBJECT_0);
我同意 David 的观点,您确实应该在主线程中完成所有 UI 工作并在工作线程中进行计算,而不是相反。
【讨论】:
它阻塞了日志窗口,因为日志窗口实际上是在主线程中创建的,因此使用了被WaitForSingleObject
阻塞的主线程消息泵。
这解释了日志窗口冻结,但不是为什么工作线程没有终止所以WaitForSingleObject()
可以解除阻塞。除非工作线程正在向日志窗口发送消息并由于无法处理消息而陷入死锁。或者如果主线程没有将WM_QUIT
消息发布到工作线程的消息队列。
由于应用程序似乎正在运行,因此来自工作线程的窗口访问有效。因此它可能是通过消息完成的,因此同步到拥有日志窗口的主线程上。如果主线程在 WaitForSingleObject 中,我猜他们会死锁。以上是关于等到消息循环在另一个线程上时窗口关闭的主要内容,如果未能解决你的问题,请参考以下文章