在我的C ++应用程序中,我有一个后台线程可以完成一些工作,将结果放入堆分配的内存块中,并调用PostMessage将结果传递给主线程。
通常,当Window收到消息时,它会处理结果,然后对delete
指定的内存执行lParam
。
但我担心窗口可能会在处理消息和删除内存之前退出。
PostMessage
以某种方式保证目标窗口有机会处理消息吗?
如果没有,是否有任何众所周知的技术可以知道Window是否释放了内存,或者后台线程是否需要负责删除它?
答案 0 :(得分:2)
PostMessage
肯定会被放入接收窗口的消息队列中。但是,无法保证窗口会在那里。它可能在那个时候被摧毁了。
帮助确保消息的一种方法是创建自己的隐藏窗口(COM经常使用此技术)并将其发布到其队列中。这样你就可以控制隐藏窗口的销毁时间。我们在实时数据传输中使用了这种方法多年。
让后台线程删除内存是一个坏主意,可能导致竞争条件,它不知道什么时候可以删除。最好发布到您自己的窗口,并在完成后将其删除。
答案 1 :(得分:2)
考虑UI线程的经典消息循环:
MSG msg;
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
将从其他线程发布的消息将被提取和分派,但其传递取决于目标窗口是否已成功创建(尚未销毁)。如果您可以控制它,可以考虑直接在消息循环中处理消息。然而,当存在另一个(嵌套的)消息循环时,事情会变得复杂,这可以通过处理某些Windows消息来创建。一个简单的例子就是一个模态对话框,但是一些更复杂的东西,比如COM调用,也会产生嵌套的消息循环。
因此,您不应该依赖有保证的邮件传递。考虑使用全局数据结构(如队列或列表(受到与关键部分的同时访问)来对数据对象进行排队。然后你仍然可以使用PostMessage
发布消息并在lParam
中传递指向数据对象的指针,但是在消息处理程序中,你需要在全局队列和进程中找到对象(或丢弃) )之前排队的对象,但由于某种原因尚未处理。通常,当您的线程退出时(WM_QUIT
消息到达上面的循环中),您应该对队列中剩余的内容进行一些处理。