• 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);
    然后调试运行,一切工作正常。

  • 相关阅读:
    log4net使用封装,无缝切换 dotnet 和 dotnetcore
    使用 certbot 申请泛域名https证书
    StackExchange.Redis中文使用文档
    在 asp.net core 中使用类似 Application 的服务
    不一样的 SQL Server 日期格式化
    你可能不知道的 docker 命令的奇淫怪巧
    [k8s]dashboard1.8.1搭建( heapster1.5+influxdb+grafana)
    [k8s]k8s 1.9(on the fly搭建) 1.9_cni-flannel部署排错 ipvs模式
    [k8s] kubelet单组件启动静态pod
    [svc]runinit管理多进程
  • 原文地址:https://www.cnblogs.com/love6tao/p/6825433.html
Copyright © 2020-2023  润新知