MFC关于多线程中传递窗口类指针时ASSERT_VALID出错的另类解决 转
MFC关于多线程中传递窗口类指针时ASSERT_VALID出错的另类解决
在多线程设计中,许多人为了省事,会将对话框类或其它类的指针传给工作线程,而在工作线程中调用该类的成员函数或成员变量等等。
但是在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
// 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);
然后调试运行,一切工作正常。
MFC关于多线程中传递窗口类指针时ASSERT_VALID出错的另类解决 转的更多相关文章
- MFC类中获得其它类指针
当用VC++的Application Wizard生成除了CDialog Basiced以外的应用程序时,将自动产生视图类.文档类.主帧窗口类.应用程序类等等.一般来说,程序的核心数据及操作在文档类中 ...
- Delphi XE增强的RTTI妙用--动态创建包中的窗口类
以前要在运行时创建package中的form类,必须要在form单元文件中这样注册类: Initialization RegisterClass(TForm3);Finalization UnRe ...
- 当this指针成为指向之类的基类指针时,也能形成多态
this指针: 1)对象中没有函数,只有成员变量 2)对象调用函数,通过this指针告诉函数是哪个对象自己谁. #include<iostream> using namespace std ...
- asp.net mvc视图中使用entitySet类型数据时提示出错
asp.net mvc5视图中使用entitySet类型数据时提示以下错误 检查了一下引用,发现已经引用了System.Data.Linq了,可是还是一直提示出错, 后来发现还需要在Views文件夹下 ...
- 在IDEA中使用JDBC获取数据库连接时的报错及解决办法
在IDEA中使用JDBC获取数据库连接时,有时会报错Sat Dec 19 19:32:18 CST 2020 WARN: Establishing SSL connection without ser ...
- Servlet中response.sendRedirect()跳转时不能设置target的解决办法
一般使用Struts2的拦截器(或者是filter)验证是否登录的时候,如果用户没有登录则会跳转到登录的页面.这时候一般可以在拦截器或者filter中用response.sendRedirect(). ...
- Quartus14.1中Qsys创建custom component时编译出错原因
利用Quartus14.1中Qsys工具新建自定义组件时会产生“part-select direction is opposite from prefix index direction”错误,这是由 ...
- delphi中WebBrowser的parent改变时变成空白问题的解决(覆盖CreateWnd和DestroyWnd)
这段时间在做一个delphi界面打开网页的功能,且此网页所在窗口可完整显示,可缩小到另一个窗口的panel上显示 可是在改变网页所在窗口时,WebBrowser控件变成了空白 上网google了半天, ...
- 在win10环境中安装xilinx vivado IDE时出现的问题及解决方法
1.问题:There is no valid Xilinx installation that this Update can be applied to. 解决方法一:下载的是更新包,如果设备没有预 ...
随机推荐
- 树莓派小车(三)Python控制小车
正文之前 由于最近忙于复习赶考,所以暂时没有拿起树莓派小车,直到昨天,终于空出时间来把代码整理一下来和大家分享. 正文 在树莓派小车系列之二中,讲到了树莓派的引脚定义方式有两种: PHYSICAL N ...
- WPF Effect 造成的字体模糊
WPF 里面有个Effect ,暂且可以理解为 "特效" 分类. 但是有时候使用不恰当,容易出现各种毛病. 例如: 代码如下: <StackPanel HorizontalA ...
- Google 搜索引擎语法
Google Hack原理很简单,就是利用搜索引擎强大的搜索能力,来查找一些存在漏洞的网站.要利用Google来查找网站的漏洞自然要学会Google这个搜索引擎的语法了.下面先给大家讲解一下Googl ...
- laravel中实现短信发送验证码
前段时间想实现一个短信验证码的功能,但是卡了很长时间. 首先我用的是阿里云的短信服务业务,其首次接入流程如下: 在阿里云上开通短信服务后需要做的: 1,申请签名 2,申请模板 3,创建Acces ...
- 用Eclipse Maven 创建 Web 3.0 项目问题 正确的处理步骤
在Eclipse 安装好Maven插件后,创建Maven webapp项目,在工程 properties -> project facets 界面中将 Dynamic Web Module 修改 ...
- .NET中的按需加载/延迟加载 Lazy<T>
业务场景: 在项目开发中,经常会遇到特定的对象使用的加载问题,有的实例对象我们创建之后并非需要使用,只是根据业务场景来调用,所以可能会导致很多无效的实例加载 延迟初始化出现于.NET 4.0,主要用于 ...
- SmileyFace——基于OpenCV的人脸人眼检测、面部识别程序
项目地址 https://github.com/guoyaohua/SmileyFace 开发环境 Visual Studio 2010 MFC + OpenCV 功能描述 静态图像人脸检测 视频人脸 ...
- HDU - 4496 City 逆向并查集
思路:逆向并查集,逆向加入每一条边即可.在获取联通块数量的时候,直接判断新加入的边是否合并了两个集合,如果合并了说明联通块会减少一个,否则不变. AC代码 #include <cstdio> ...
- hdu1251 map水过
更快的方法应该是字典树,不用处理前缀. AC代码: #include<iostream> #include<cstring> #include<string> #i ...
- UART知识总结
一.定义 通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常称作UART. 二.时序 上图是uart协议传输一个"A" ...