【问题标题】:MFC: Is it safe to call CWnd methods from another thread?MFC:从另一个线程调用 CWnd 方法是否安全?
【发布时间】:2018-06-30 22:22:03
【问题描述】:

其实我有两个问题:

  1. 从工作线程调用SendMessage 是否安全?
  2. CWnd 方法,如MessageBox,是否在后台调用 API 函数 SendMessage

据我了解,当工作线程调用SendMessage时,它会将消息推送到UI线程的消息队列中,并等待该消息被处理。在这种情况下,这样做是安全的。

对此我不太确定。如果我错了,请纠正我。

非常感谢。

------------ 更新 ---------- ------------

作为结论:

  • 跨线程调用 Windows API ::SendMessage::PostMessage 是安全的。
  • 跨线程调用CWnd 方法是不安全的。有些方法可能是安全的,但不能保证。

非常感谢大家。

【问题讨论】:

标签: c++ multithreading mfc sendmessage cwnd


【解决方案1】:

从工作线程调用SendMessage 是否安全?

是的。系统确保消息处理在接收线程上序列化。当跨线程发送消息时,发送者被阻塞,直到消息被处理。接收方在执行消息检索代码(GetMessagePeekMessage等)时只处理跨线程发送的消息。发送的消息永远不会在消息队列中排队。 SendMessage 的文档有更多详细信息。

CWnd 方法,如 MessageBox,是否在后台调用 API 函数 SendMessage

是的。一方面,消息框将接收标准窗口消息,如WM_CREATEWM_NCCREATE 作为对话框构造的一部分。此外,对于拥有的窗口(如模式对话框),系统将发送WM_ACTIVATE 消息到正在停用的窗口和正在激活的窗口。不过,我不确定为什么这很重要,或者您为什么特别提出这个问题。

现在是你标题中的问题:

从另一个线程调用CWnd 方法是否安全?

一般来说,不会。不过,这确实取决于成员。有些可以安全调用,有些则不能。特别是,所有修改窗口状态(内容、可见性、激活等)的方法都只能从创建窗口的线程中调用。如果调用不安全,系统仍将处于一致状态。但是,您的应用程序可能不是。

【讨论】:

  • 非常感谢您的回答。实际上,我正在尝试从工作线程将进度信息更新到 UI。我想知道直接在窗口上调用CWnd::SetWindowText 是否安全。由于SendMessage是线程安全的,如果CWnd::SetWindowText调用SendMessage,那么我认为直接调用CWnd::SetWindowText也是安全的。对吗?
  • 可能是的,但这取决于。正如 IInspectable 所说。但在 SendMessage 之前,我总是用 GetSafeHwnd() 检查 CWnd。因为如果m_hWnd 无效,SendMessage 会抛出一个AfxThrowInvalidArgException
  • @KenZhang 这将是一个非常糟糕的设计,因为工作线程不应该关心 UI,而只是通知 UI 线程有关进度。这应该通过带有WM_APP+x 消息ID 的PostMessage() 来完成,以解耦线程。如果您不小心,SendMessage() 很容易死锁(例如,如果您在 UI 线程使用 WaitForSingleObject() 或类似 API 等待线程时调用它)。此外,您不希望工作线程在 UI 更新时空闲(这可能很耗时),这是PostMessage() 的另一个好理由。
【解决方案2】:

线程访问 UI 的唯一方式是使用SendMessagePostMessage

考虑一台具有一个内核的机器,其中发生上下文切换并且您从工作线程直接访问 UI,您可能会损坏 UI 线程寄存器!

基本上每个 UI 框架都提供了一种机制(很多次),用于从线程进行 UI 更改。例如,Android 提供ASyncTaskHandler

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-13
    • 1970-01-01
    • 2011-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-12
    相关资源
    最近更新 更多