9

在我的 C++ 应用程序中,我有一个后台线程来完成一些工作,将结果放入堆分配的内存块中,然后调用PostMessage将结果传递给主线程。

通常,当 Window 接收到消息时,它会处理结果,然后deletelParam.

但我担心窗口可能会在处理消息和删除内存之前退出。

是否PostMessage以某种方式保证目标窗口将有机会处理消息?
如果没有,是否有任何众所周知的技术可以知道 Window 是否释放了内存,或者后台线程是否需要负责删除它?

4

2 回答 2

2

PostMessage肯定会被放入接收窗口的消息队列中。但是,不能保证窗口会在那里。到那个时候,它可能已经被摧毁了。帮助确保消息到达那里的一种方法是创建您自己的隐藏窗口(COM 经常使用这种技术)并发布到它的队列。这样你就可以控制隐藏窗口何时被销毁。我们多年来一直在实时数据传输中采用这种方法。

让后台线程删除内存是一个坏主意,并且可能导致不知道何时可以删除的竞争条件。最好发布到您自己的窗口并在完成后将其删除。

于 2013-09-12T16:14:21.387 回答
2

考虑 UI 线程的经典消息循环:

   MSG msg;
   while(GetMessage(&msg, NULL, 0, 0) > 0)
   {
     TranslateMessage(&msg);
     DispatchMessage(&msg);
   }

您从另一个线程发布的消息将被获取并发送,但它的发送取决于目标窗口是否已成功创建(并且尚未销毁)。如果您可以控制它,您可以考虑直接在消息循环中处理消息。然而,当存在另一个(嵌套的)消息循环时,事情可能会变得复杂,这可能是由于处理一些 Windows 消息而创建的。一个简单的例子是模态对话框,但一些更复杂的东西,如 COM 调用也可能导致嵌套的消息循环。

因此,您不应依赖有保证的消息传递。考虑使用像队列或列表这样的全局数据结构(通过临界区防止同时访问)来对数据对象进行排队。然后,您仍然可以使用 in 发布消息PostMessage并将指针传递给您的数据对象lParam,但在您的消息处理程序中,您需要在全局队列中定位对象并处理(或丢弃)之前排队的对象,但是对于某些原因尚未处理。通常,当您的线程退出时(WM_QUIT消息到达上面的循环),您也应该对队列中剩余的任何内容进行一些处理。

于 2013-09-12T16:31:52.013 回答