前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >windows窗体线程异常_指针在声明和使用时有何不同

windows窗体线程异常_指针在声明和使用时有何不同

作者头像
全栈程序员站长
发布2022-10-04 11:02:05
4810
发布2022-10-04 11:02:05
举报

大家好,又见面了,我是你们的朋友全栈君。 在多线程设计中,许多人为了省事,会将对话框类或其它类的指针传给工作线程,而在工作线程中调用该类的成员函数或成员变量等等。 但是在Debug版本时,在某些情况下,特别是在工作线程中调用pWnd->UpdateData(FALSE)时,会出现错误。 这个错误的原因网上有许多地方讲到了,但是,令人失望的是,讲得好的没几篇,都是非要讲什么线程模块状态什么的,让人看得云里雾里(不过,说实话,也就是从这些文章中才知道是怎么回事的)。

其实本人以为,说穿了,很简单,避免多线程冲突,下面举例说明:

在你的对话框类中有一编辑框和一按钮,编辑框关联了变量为m_strText

现在在你按下按钮时,你有代码如下: m_strText = “Hello”; UpdateData(FALSE);

在正常情况下你的编辑框中很显然会显示出”Hello”来。 但是,不怕一万,就怕万一,偏偏在你m_strText=”Hello”这个代码执行之后,你的线程切换了,可是在你的工作线程里,你却将m_strText设置成了”Sorry”,结果当线程切换回来后,UpdateData(FALSE)后,编辑框上就变成”Sorry”而不是”Hello”了。

所以,MFC并不建议这种多线程中传递MFC对象的指针,而且MFC人为的加了一个ASSERT_VALID来表示它们的不建议。

但是,不建议并不表示不能用,如果你能够确认你的线程不会互相冲突,你就大胆的用吧。 正因为如此,MFC只是在Debug版本中才有这个ASSERT_VALID的问题存在,在Release版本中却没有,因为它没有理由来阻止我们用。

虽然如此,但是毕竟我们的调试许多时候是要用到Debug版本的,MFC的如此做法还是给我们带来了诸多不变,幸运的是,MFC将它的真正检测线程相关MFC对象的代码做成了虚拟函数,也就是说,我们可以重载它,这样在Debug时,也不会出这问题了。

下面,让我们热烈欢迎我们今天的主角出场-- virtual void CObject:: AssertValid( ) const; ASSERT_VALID最后会调用MFC类对象的AssertValid函数,因此只要重载AssertValid,令其不检测与线程相关的这些东东,就不会弹出出错框了(其实这些出错框,本来就是人为的弹出来的)。

费话就不说了,假设我们的对话框是CTmthDlg,下面是重载后的代码

void CTmthDlg::AssertValid() const { if (m_hWnd == NULL) return; // null (unattached) windows are valid

// check for special wnd??? values ASSERT(HWND_TOP == NULL); // same as desktop if (m_hWnd == HWND_BOTTOM) ASSERT(this == &CWnd::wndBottom); else if (m_hWnd == HWND_TOPMOST) ASSERT(this == &CWnd::wndTopMost); else if (m_hWnd == HWND_NOTOPMOST) ASSERT(this == &CWnd::wndNoTopMost); else { // should be a normal window ASSERT(::IsWindow(m_hWnd));

// should also be in the permanent or temporary handle map /* CHandleMap* pMap = afxMapHWND(); ASSERT(pMap != NULL);

CObject* p; ASSERT((p = pMap->LookupPermanent(m_hWnd)) != NULL || (p = pMap->LookupTemporary(m_hWnd)) != NULL); ASSERT((CWnd*)p == this); // must be us */ // Note: if either of the above asserts fire and you are // writing a multithreaded application, it is likely that // you have passed a C++ object from one thread to another // and have used that object in a way that was not intended. // (only simple inline wrapper functions should be used) // // In general, CWnd objects should be passed by HWND from // one thread to another. The receiving thread can wrap // the HWND with a CWnd object by using CWnd::FromHandle. // // It is dangerous to pass C++ objects from one thread to // another, unless the objects are designed to be used in // such a manner. } }

这里我只是简单的从CWnd::AssertValid中拷贝来,然后注释掉检测线程中MFC对象和Windows对象映射的代码。

另外,请注意一下MFC自己的一些注释。 // It is dangerous to pass C++ objects from one thread to // another, unless the objects are designed to be used in // such a manner.

现在,请在你的工作线程中调用 ((CTmthDlg*)pParam)->UpdateData(FALSE); 然后调试运行,一切工作正常。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年9月5日 下,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档