是CWnd :: GetSafeHwnd()和CWnd :: m_hWnd ThreadSafe?

时间:2012-02-17 16:43:18

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

我面临着大量多线程应用程序的大量崩溃。

阅读这些MSDN pagetechnical notethis article on TLS,我了解到CWnd个对象被映射到线程本地Storgae中的HWND(TLS,这是一个线程依赖性内存访问)。

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

但是我的一位同事真的坚持认为我只是将CWnd*保留在外国人话题中,采用::PostMessage政策确定,但使用CWnd::GetSafeHwnd()pMyCWnd->m_hWnd外部线程,以便恢复本机HWND

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

我错了? MSDN显然使用了术语意外结果

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

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

3 个答案:

答案 0 :(得分:10)

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

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

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

如果这给您带来麻烦(因为它没有明确记录),那么只需复制一份HWND并让线程访问它。

P.S。 Here's the article you linked to英文版。

答案 1 :(得分:5)

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

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

答案 2 :(得分:1)

如果你有一个多线程应用程序,其中多个线程都试图一次访问HWND,听起来像你有一个设计问题。你不能限制你的线程进行计算,并处理主线程上的UI问题吗?这是一个优秀的多线程应用程序的典型设计。