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出错的另类解决 转的更多相关文章

  1. MFC类中获得其它类指针

    当用VC++的Application Wizard生成除了CDialog Basiced以外的应用程序时,将自动产生视图类.文档类.主帧窗口类.应用程序类等等.一般来说,程序的核心数据及操作在文档类中 ...

  2. Delphi XE增强的RTTI妙用--动态创建包中的窗口类

    以前要在运行时创建package中的form类,必须要在form单元文件中这样注册类: Initialization  RegisterClass(TForm3);Finalization  UnRe ...

  3. 当this指针成为指向之类的基类指针时,也能形成多态

    this指针: 1)对象中没有函数,只有成员变量 2)对象调用函数,通过this指针告诉函数是哪个对象自己谁. #include<iostream> using namespace std ...

  4. asp.net mvc视图中使用entitySet类型数据时提示出错

    asp.net mvc5视图中使用entitySet类型数据时提示以下错误 检查了一下引用,发现已经引用了System.Data.Linq了,可是还是一直提示出错, 后来发现还需要在Views文件夹下 ...

  5. 在IDEA中使用JDBC获取数据库连接时的报错及解决办法

    在IDEA中使用JDBC获取数据库连接时,有时会报错Sat Dec 19 19:32:18 CST 2020 WARN: Establishing SSL connection without ser ...

  6. Servlet中response.sendRedirect()跳转时不能设置target的解决办法

    一般使用Struts2的拦截器(或者是filter)验证是否登录的时候,如果用户没有登录则会跳转到登录的页面.这时候一般可以在拦截器或者filter中用response.sendRedirect(). ...

  7. Quartus14.1中Qsys创建custom component时编译出错原因

    利用Quartus14.1中Qsys工具新建自定义组件时会产生“part-select direction is opposite from prefix index direction”错误,这是由 ...

  8. delphi中WebBrowser的parent改变时变成空白问题的解决(覆盖CreateWnd和DestroyWnd)

    这段时间在做一个delphi界面打开网页的功能,且此网页所在窗口可完整显示,可缩小到另一个窗口的panel上显示 可是在改变网页所在窗口时,WebBrowser控件变成了空白 上网google了半天, ...

  9. 在win10环境中安装xilinx vivado IDE时出现的问题及解决方法

    1.问题:There is no valid Xilinx installation that this Update can be applied to. 解决方法一:下载的是更新包,如果设备没有预 ...

随机推荐

  1. linux指令札记

    1.有关文件压缩解压缩:Linux下自带了一个unzip的程序可以解压缩文件,解压命令是:unzip filename.zip 同样也提供了一个zip程序压缩zip文件,命令是 zip filenam ...

  2. BZOJ 3669: [Noi2014]魔法森林 [LCT Kruskal | SPFA]

    题目描述 为了得到书法大家的真传,小 E 同学下定决心去拜访住在魔法森林中的隐 士.魔法森林可以被看成一个包含 n 个节点 m 条边的无向图,节点标号为 1,2,3,…,n,边标号为 1,2,3,…, ...

  3. 数组的复制及ES6数组的扩展

    一.数组的复制 // alert([1,2,3]==[1,2,3]); let cc = [0,1,2]; let dd = cc; alert(dd==cc);//此时改变dd会影响cc ES5 只 ...

  4. MUI体验框架

    1.      mui简介 1.1  缘起 1.基于jq的jqmobile,性能低的无法忍受,且UI难看 2.bootstrap这种响应式设计,性能在低端机不足,而且UI风格一看就是网页,不是App的 ...

  5. ThinkPHP删除栏目(单)

    当我们做一些网站项目的时候,都会遇到这样一类问题,删除一个栏目,而这个栏目又不是最底层栏目,也就是说,被删除的栏目拥有子栏目,这时,我们执行删除该栏目的命令,就需要将该栏目及其子栏目一并删除,因为我们 ...

  6. linux常用命令(不断更新)

    睡眠命令(第一步可省去): 1.查看你的系统支持什么模式:cat /sys/power/state(我的系统为:freeze mem disk) 2.切换到管理员模式下,执行命令:echo " ...

  7. ORM规约变更经典案例---mysql军规

    先介绍一下<MySQL数据库开发的三十六条军规>,这里只介绍核心的,具体内容大家可以自行百度,这是从底层开发人员到管理者必须知道规范.出自58赶集. 写在前面的话: 总是在灾难发生后,才想 ...

  8. Windows Server 2016-WinSer2016 Active Directory新增功能

    Windows Server 2016 Active Directory 域服务 (AD DS)新增很多功能用来提升Active Directory域及组织环境安全等,并帮助他们面向云的部署或混合部署 ...

  9. 讲解mybaits的标签语法

    前言:mybatis作为一个持久层的java框架,高度封装了jdbc原始代码,它拥有比Hiberante更便捷.更直接的sql语法和sql灵活配置的特性,比如简单的一个自动映射对象就大大减少了我们的代 ...

  10. kubernetes 集群的安装部署

    本文来自我的github pages博客http://galengao.github.io/ 即www.gaohuirong.cn 摘要: 首先kubernetes得官方文档我自己看着很乱,信息很少, ...