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. BZOJ 1969: [Ahoi2005]LANE 航线规划 [树链剖分 时间倒流]

    题意: 一张图,删除边,求两点之间的割边数量.保证任意时刻图连通 任求一棵生成树,只有树边可能是割边 时间倒流,加入一条边,就是两点路径上的边都不可能是割边,区间覆盖... 然后本题需要把边哈希一下, ...

  2. BZOJ 3790: 神奇项链 [Manacher 贪心]

    3790: 神奇项链 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 405  Solved: 200[Submit][Status][Discuss] ...

  3. Oracle的order by的中文排序问题

    Oracle 中查询结果按照某个中文字段或者英文字母(包括 符号)排序,并不会得到我们预期的结果,因为对于中文与英文字母及符号,Oracle实际是按照其对应的ASCII码值排序的! 可以看到按照中文村 ...

  4. VirtualDOM与diff(Vue实现)

    写在前面 因为对Vue.js很感兴趣,而且平时工作的技术栈也是Vue.js,这几个月花了些时间研究学习了一下Vue.js源码,并做了总结与输出.文章的原地址:https://github.com/an ...

  5. MySql主键自动生成,表、实体、C#调用方法

    1.表:mysql建表语句 DROP TABLE IF EXISTS `keycode`; CREATE TABLE `keycode` ( `Id` ) NOT NULL AUTO_INCREMEN ...

  6. 【学习笔记】Hibernate关联映射(Y2-1-6)

    Hibernate关联映射 关联映射就是将关联关系映射到数据库里,在对象模型中就是一个或多个引用. 1.单向多对一关联 准备数据库 部门表和员工表 其中部门表有两列 部门编号和名称 员工表有三列 员工 ...

  7. Java注释用处

    1.Java注释: import cn.lonecloud.Doc; /** * Created by lonecloud on 2017/8/17. * 测试注释类型 {@link Doc#test ...

  8. CentOS7上安装并配置Nginx、PHP、MySql

    一.Nginx 1.安装nginx yum install nginx 2.启动nginx systemctl start nginx 除了systemctl start nginx之外,常用的相关命 ...

  9. Windows下Nginx的启动、停止等基本命令

    在Windows下使用Nginx,我们需要掌握一些基本的操作命令,比如:启动.停止Nginx服务,重新载入Nginx等,下面我就进行一些简单的介绍. 1.启动: C:\server\nginx-1.0 ...

  10. Zend Framework在windows下的安装

    1:首先需要下载安装PHP的依赖管理工具Composer 详情去http://docs.phpcomposer.com/了解 下载链接: https://getcomposer.org/downloa ...