PostMessage可以在GetMessage之后在UI线程中显示工作线程中变量的变化吗?

时间:2013-12-22 05:03:26

标签: c++ windows multithreading

我的问题实际上是,如果我在另一个线程中写一个变量,然后PostMessage写一个Wnd,那么UI线程中的GetMessage会与它同步,我可以安全地读取变量吗?

背景是:我想使用PostMessage从后台线程更新UI,并担心数据争用。我需要其他同步工具吗?

感谢。

编辑: 标题非常混乱,所以改变它。

详细说明案例: 假设我想要更新std::string,这是一个全局变量。由于我在string之前更新PostMessage,我是否可以安全地阅读处理该消息的Window Proc中的string

我熟悉C ++ 11多线程术语,如happens-beforesequence-beforesynchronize-withrelease-acquire概念,所以我的问题可以告诉其他人方式:

在阅读之前写string是否会发生?

PS:并且假设这是一次性事情,工作线程不会一次又一次地更新string

4 个答案:

答案 0 :(得分:2)

Windows消息队列是线程安全的生产者 - 消费者队列。 MSG结构(并且只有那个)被COPIED到队列中,所以一旦发布了消息,你就可以重新加载你自己的消息数据和PostMessage而没有任何问题。

当开发人员PostMessage指针/引用为wParam,lParam时,生命周期出现问题。如果指针指向本地堆栈对象,则可以在接收GetMessage / wndProc中处理指向它的指针之前将其转换为RAII。类似地,如果在GetMessage线程中处理指向使用new实例化的对象的指针,则在发布线程中显式删除该指针。

如果您提供有关PostMessaging数据的更多详细信息,我们应该能够为您提供建议。

答案 1 :(得分:2)

没有。你没有控制权。 PostMessage是真正异步的,当处理消息时,两个线程中发生了很多事情(包括处理先前发布的消息和发送消息(通过SendMessage)。

根据您的目的,您可以:

  1. 异步传输数据副本(malloc / new)和PostMessagewParamlParam中的指针)
  2. 使用SendMessage
  3. 同步传输指向数据的指针
  4. 使用SendMessageWM_COPYDATA
  5. 同步传输数据副本

答案 2 :(得分:2)

它可以保证UI线程将使用数据并可以安全地更新窗口。那就是结束的地方,你仍然有另一个线程,它从一个写入数据的线程中读取数据,因此需要正常的联锁以确保UI线程不会读取更改数据。

这是一个常见的问题,当 UI线程检索到消息时,您无法确切地知道。如果UI线程陷入困境,可能需要很长时间。因此,除非您明确地握手,否则您无法知道您的工作线程何时可以继续更新数据或何时可以发布另一条消息。创建数据的深层副本可以解决这个问题。或者你需要一个自动重置事件来握手,要小心它能够导致死锁。

您必须处理的另一种可能的故障模式是PostMessage()可能会失败。当UI线程因任何原因陷入困境时会发生这种情况,只要消息队列大小超过配额(默认情况下为10,000条消息),您将获得FALSE返回。你可以做的很少但是睡一会然后再试一次。

当您遇到火管问题时,您也会调用此故障模式,工作线程以比UI线程可以跟上的速度更快的速度生成数据。消防功能特别棘手,因为当您使用有限的数据集启动或调试程序时很少发生。诊断是丢失了WM_PAINT通知,即使UI仍处于活动状态并且主动处理已发布消息的积压,您的UI也会冻结。您可以通过保持人眼可以感知UI更新速率的北方来避免这种情况。这是好的和慢的,当你每秒更新超过25次时,它变成一个难以理解的模糊。

答案 3 :(得分:0)

PostMessage / GetMessage的文档未对synchronize-with关系提供任何保证。因此,即使当前/最新版本的Windows在您的硬件平台上为synchronize-with / PostMessage提供了GetMessage实际关系,您也不应该依赖它,因为它可以在较新版本中更改Windows或它可能无法在其他硬件平台上运行。因此,在特定情况下,您必须自己提供synchronize-with关系,以使您的多线程代码具有防范性。例如,您可以使用InterlockedXxx函数(它们同时具有获取和释放语义)或std :: atomic。