【问题标题】:Is CWnd::GetSafeHwnd() and CWnd::m_hWnd ThreadSafe?CWnd::GetSafeHwnd() 和 CWnd::m_hWnd 是线程安全的吗?
【发布时间】:2012-02-17 16:43:17
【问题描述】:

我在一个高度多线程的应用程序上面临许多崩溃。

看了这些MSDNpagetechnical notethis article on TLS,我了解到CWnd对象映射到Thread Local Storgae中的HWND(TLS,这是一个线程依赖的内存访问)。

我打算解耦所有看起来像 CWnd 线程远程访问的东西,并将其转换为 HWND 引用,然后使用 ::PostMessage 作为通信端口。

但是我的一位同事真的坚持我只保留外线程中的CWnd*,采用::PostMessage策略ok,但是在外线程中使用CWnd::GetSafeHwnd()pMyCWnd->m_hWnd以便恢复原生HWND

我一直在争论 nowhere 我已经看到 GetSafeHwnd() 是线程安全的,并且 CWnd 对象在 TLS 中,它在另一个线程中的值是不同的。

我错了? MSDN 显然使用了Unexpected results这个术语。

对于从创建者线程在外线程中调用CWnd::GetSafehwnd()pMyCWnd->m_hWnd,您的观点是什么?

您是否有任何 MSDN 文档说明这是否安全。

【问题讨论】:

    标签: c++ multithreading winapi thread-safety thread-local-storage


    【解决方案1】:

    CWnds 没有映射到 HWNDs; HWND 被映射到 CWnd,这发生在每个线程的基础上。 CWnd 对象不在 TLS 中(这将如何工作?),但临时 CWnd 对象是按线程创建的。

    从错误的线程访问 临时 CWnd 对象绝对是个坏主意(原因由 Mark Ransom 描述)。

    但是,如果您有一个永久的 CWnd 对象(例如,表示您的应用程序的主窗口),那么一旦创建它,​​从任何线程访问 m_hWnd 成员都没有问题。它只是内存中的一个永远不会改变的值。

    如果这给您带来困扰(因为它没有明确记录),那么只需制作 HWND 的副本并让线程访问它。

    附: Here's the article you linked to 英文。

    【讨论】:

      【解决方案2】:

      GetSafeHwnd 只是一个简单的包装器,它检查 this 是否为 NULL,如果不是则返回 m_hWnd,如果是则返回 NULL。它不会比m_hWnd 本身更线程安全。

      当您创建临时 CWnd* 时,MFC 将在它认为安全的点将其销毁,例如下一次通过消息循环。如果您有多个使用 MFC 的线程,那么您的临时对象可能会在您仍在使用它时被破坏。您可以从您的线程中执行的任何操作都不会检测到此错误。

      【讨论】:

      • 是否都是 CWnd* 临时的?我的意思是在实例化窗口时在创建者线程中创建的一个 CWnd*,它也是临时的吗??? (我的意思不是通过 CWnd::FromHandle() 计算的那些)
      【解决方案3】:

      如果您有一个多线程应用程序,其中多个线程都试图同时访问 HWND,那么在我看来,您可能遇到了设计问题。你不能限制你的线程进行计算,并在主线程上处理 UI 问题吗?这就是优秀多线程应用的典型设计。

      【讨论】:

      • 不错的建议,但我无法重新编码整个事情,许多 LOC,而且它已有 10 多年的历史,我无法抹去它的巨大历史 :-)
      • 嗯,你的问题基本上是“我必须做这个极其不安全的事情,安全吗?”答案可能是“没有什么能让它变得安全”。您可以在一定程度上使其更安全,但我怀疑它能否在当前设计中实现无崩溃。
      • (顺便说一句,我可以理解。我还在一个 10 年前的 MFC 代码库上工作。谢天谢地,我们没有线程;最初的编码人员还不够聪明,无法做到这一点。)
      • 我不同意你的说法。如果我在 HWND 上执行 ::PostMessage,它看起来会更安全一些,因为它将执行更新的泵消息窗口的线程。也许不是最好的设计,我完全同意。我的问题基本上是“是 GetSafeHwnd() 还是 CWnd::m_hWnd 线程安全”,您还没有回答。 ;-)。
      • 哦,正如其他人所提到的,临时 CWnd* 非常不安全。事实上,我认为它们在单线程代码中也相当不安全。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-06-30
      • 1970-01-01
      • 1970-01-01
      • 2010-12-03
      • 2021-11-07
      • 1970-01-01
      • 2017-06-07
      相关资源
      最近更新 更多