【问题标题】:Using SendMessage() Multi-threaded使用 SendMessage() 多线程
【发布时间】:2016-02-22 00:29:46
【问题描述】:

如果我从不同的线程使用 SendMessage() 到一个接收器会发生什么?想象一种情况,当接收者仍在处理来自 Thread1 的消息,而 Thread2 发送另一条消息(使用 SendMessage())。接收端会发生什么?它是否停止执行 Message1,处理 Message2 并在完成 Message2 后返回 Message1?还是 Message2 等待 Message1 结束?

【问题讨论】:

  • 如果代码进入可更改的等待状态,Message1 可能在该处理期间被抢占,这将允许 Message2 得到处理。所以不能保证消息处理的顺序和原子性。
  • 第二条消息在线程调用消息处理函数时分派。

标签: c++ windows multithreading winapi message-queue


【解决方案1】:

基本规则是:线程调度跨线程发送消息的唯一时间是在该线程上调用消息检索函数(GetMessagePeekMessage 等)时。消息检索函数首先检查是否有任何跨线程发送的消息,一个接一个地发送它们,然后继续从线程的消息队列中检索消息。

这有两个后果:

  • 当接收线程未处理1)任何排队的消息时,将调度跨线程发送的消息。
  • 当接收线程未处理1)任何其他跨线程发送的消息时,将调度跨线程发送的消息。

在您的特定示例中,接收方将继续处理 Message1 直到完成,并在下次调用消息检索函数时继续调度 Message2。

此规则有一个值得注意的例外:等待SendMessage 返回的线程可以调度入站跨线程发送的消息2)。这意味着有可能重新进入。再次以您的示例为例,假设 Message1 的消息处理程序在某些时候调用 SendMessage,很可能是在继续处理 Message1 之前调度了 Message2。

总结一下:

  • 跨线程发送的消息在接收线程上串行调度。
  • 当一个线程分派跨线程发送的消息时,有几个明确定义的时间。
  • 虽然跨线程发送的消息永远不会同时处理,但没有原子性规则;为重新进入做好准备。


1) 假设调用消息检索函数不是正常消息处理的一部分。
2) 请参阅When can a thread receive window messages? 了解为什么会这样。

【讨论】:

    【解决方案2】:

    我假设问题是关于发送到特定窗口的消息,即除 NULL 或 HWND_BROADCAST 之外的 HWND,并且该窗口由属于同一进程的线程拥有。

    在这种情况下,创建目标窗口的线程将在下次使用包含给定窗口的过滤器调用 GetMessage 时收到消息。发送线程将被阻塞,直到接收线程真正完成对消息的处理。

    如果在处理来自 Thread1 的消息时,接收线程再次调用 GetMessage/DispatchMessage,那么任何待处理的消息(包括可能由 Thread2 发送的消息)都将在该点处理,然后控制将返回到对来自的消息的处理线程1。

    来自SendMessage function 的文档:

    如果指定的窗口是由调用线程创建的,则窗口过程会立即作为子例程调用。如果指定的窗口是由不同的线程创建的,系统将切换到该线程并调用适当的窗口过程。只有当接收线程执行消息检索代码时,才会处理线程之间发送的消息。发送线程被阻塞,直到接收线程处理完消息。

    【讨论】:

    • 我一直觉得这个“切换到那个线程”的说法有争议。事实是它没有:它参与了接下来描述的帽子,这在任何意义上都不是线程切换,而是某种块和帖子。
    • @EJP 是的,措辞有点误导,最终效果就是您所描述的。 FWIW 报价直接来自官方 MSDN 文档,并且(快速检查)它至少自 2001 年以来没有改变。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多