1、 之所以是“可能”,因为这里有个重点就是临时对象是HWND操作的封装,不是窗口类的封装。因此所有的HWND临时对象都是CWnd的实例,即使上面强行转换为CAbcDialog*也依旧是CWnd*,所以在ASSERT_VALID里调用CAbcDialog::AssertValid时,其定义了一些附加检查,则可能发现这是一个CWnd的实例而非一个CAbcDialog实例,导致断言失败。因此应将CAbcDialog全部换成CWnd,这下虽然不断言失败了,但依旧错误(先不提pDialog->m_Data怎么办),因为临时对象是HWND操作的封装,而不幸的是UpdateData只是MFC自己提供的一个对话框数据交换的机制(DDX)的操作,其不是通过向HWND发送消息来实现的,而是通过虚函数机制。因此在UpdateData中调用实例的DoDataExchange将不能调用CAbcDialog::DoDataExchange,而是调用CWnd::DoDataExchange,因此将不发生任何事。

因此合理(并不一定最好)的解决方法是向CAbcDialog的实例发送一个消息,而通过一个中间变量(如一全局变量)来传递数据,而不是使用CAbcDialog::m_Data。当然,如果数据少,比如本例,就应该将数据作为消息参数进行传递,减少代码的复杂性;数据多则应该通过全局变量传递,减少了缓冲的管理费用。修改后如下:
  #define AM_DATANOTIFY ( WM_USER + 1 )
  static DWORD g_Data = 0;
  DWORD WINAPI ThreadProc( void *pData ) // 线程函数(比如用于从COM口获取数据)
  {
  // 数据获取循环
  // 数据获得后放在变量i中
  g_Data = i;
  CWnd *pWnd = CWnd::FromHandle( reinterpret_cast< HWND >( pData ) );
  ASSERT_VALID( pWnd ); // 本例应该直接调用平台SendMessage而不调用包装类的,这里只是演示
  pWnd->SendMessage( AM_DATANOTIFY, 0, 0 );
  …
  }
  BEGIN_MESSAGE_MAP( CAbcDialog, CDialog )
  …
  ON_MESSAGE( AM_DATANOTIFY, OnDataNotify )
  …
  END_MESSAGE_MAP()
  BOOL CAbcDialog::OnInitDialog()
  {
  CDialog::OnInitDialog();
  // 其他初始化代码
  CreateThread( NULL, 0, ThreadProc, m_hWnd, 0, NULL ); // 创建线程
  return TRUE;
  }
  LRESULT CAbcDialog::OnDataNotify( WPARAM /* wParam */, LPARAM /* lParam */ )
  {
  UpdateData( FALSE );
  return 0;
  }
  void CAbcDialog::DoDataExchange( CDataExchange *pDX )
  {
  CDialog::DoDataExchange( pDX );
  DDX_Text( pDX, IDC_EDIT1, g_Data );
  }

 
 

2、注意事项
  “线程安全”是一个什么概念?
  以前常听高手告诫MFC对象不要跨线程使用,因为MFC不是线程安全的。比如CWnd对象不要跨线程使用,可以用窗口句柄(HWND)代替。CSocket/CAsyncSocket对象不要跨线程使用,用SOCKET句柄代替.那么到底什么是线程安全呢?什么时候需要考虑?如果程序涉及到多线程的话,就应该考虑线程安全问题。比如说设计的接口,将来需要在多线程环境中使用,或者需要跨线程使用某个对象时,这个就必须考虑了。关于线程安全也没什么权威定义。在这里我只说说我的理解:所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题。
  一般而言“线程安全”由多线程对共享资源的访问引起。如果调用某个接口时需要我们自己采取同步措施来保护该接口访问的共享资源,则这样的接口不是线程安全的.MFC和STL都不是线程安全的. 怎样才能设计出线程安全的类或者接口呢?如果接口中访问的数据都属于私有数据,那么这样的接口是线程安全的.或者几个接口对共享数据都是只读操作,那么这样的接口也是线程安全的.如果多个接口之间有共享数据,而且有读有写的话,如果设计者自己采取了同步措施,调用者不需要考虑数据同步问题,则这样的接口是线程安全的,否则不是线程安全的。

3、多线程的程序设计应该注意些什么呢
  1、尽量少的使用全局变量、static变量做共享数据,尽量使用参数传递对象。被参数传递的对象,应该只包括必需的成员变量。所谓必需的成员变量,就是必定会被多线程操作的。很多人图省事,会把this指针(可能是任意一个对象指针)当作线程参数传递,致使线程内部有过多的操作权限,对this中的参数任意妄为。整个程序由一个人完成,可能会非常注意,不会出错,但只要一转手,程序就会面目全非。当两个线程同时操作一个成员变量的时候,程序就开始崩溃了,更糟的是,这种错误很难被重现。(我就在郁闷这个问题,我们是几个人,把程序编成debug版,经过数天使用,才找到错误。而找到错误只是开始,因为你要证明这个bug被修改成功了,也非常困难。)其实,线程间数据交互大多是单向的,在线程回调函数入口处,尽可能的将传入的数据备份到局部变量中(当然,用于线程间通讯的变量不能这么处理),以后只对局部变量做处理,可以很好的解决这种问题。
  2、在MFC中请慎用线程。因为MFC的框架假定你的消息处理都是在主线程中完成的。首先窗口句柄是属于线程的,如果拥有窗口句柄的线程退出了,如果另一个线程处理这个窗口句柄,系统就会出现问题。而MFC为了避免这种情况的发生,使你在子线程中调用消息(窗口)处理函数时,就会不停的出Assert错误,烦都烦死你。典型的例子就时CSocket,因为CSocket是使用了一个隐藏窗口实现了假阻塞,所以不可避免的使用了消息处理函数,如果你在子线程中使用CSocket,你就可能看到assert的弹出了。
  3、不要在不同的线程中同时注册COM组件。两个线程,一个注册1.ocx, 2.ocx, 3.ocx, 4.ocx; 而另一个则注册5.ocx, 6.ocx, 7.ocx, 8.ocx,结果死锁发生了,分别死在FreeLibrary和DllRegisterServer,因为这8个ocx是用MFC中做的,也可能是MFC的Bug,但DllRegisterServer却死在GetModuleFileName里,而GetModuleFileName则是个API唉!如果有过客看到,恰巧又知道其原因,请不吝赐教。
  4、不要把线程搞的那么复杂。很多初学者,恨不能用上线程相关的所有的函数,这里互斥,那里等待,一会儿起线程,一会儿关线程的,比起goto语句有过之而无不及。好的多线程程序,应该是尽量少的使用线程。这句话怎么理解呐,就是说尽量统一一块数据共享区存放数据队列,工作子线程从队列中取数据,处理,再放回数据,这样才会模块化,对象化;而不是每个数据都起一个工作子线程处理,处理完了就关闭,写的时候虽然直接,等维护起来就累了。

MFC多线程编的可能的更多相关文章

  1. iOS多线程编程之NSThread的使用

      目录(?)[-] 简介 iOS有三种多线程编程的技术分别是 三种方式的有缺点介绍 NSThread的使用 NSThread 有两种直接创建方式 参数的意义 PS不显式创建线程的方法 下载图片的例子 ...

  2. iOS多线程编程之NSThread的使用(转)

    本文由http://blog.csdn.net/totogo2010/原创 1.简介: 1.1 iOS有三种多线程编程的技术,分别是: 1..NSThread 2.Cocoa NSOperation  ...

  3. MFC 多线程

    MFC对多线程编程的支持 MFC中有两类线程,分别称之为工作者线程和用户界面线程.二者的主要区别在于工作者线程没有消息循环,而用户界面线程有自己的消息   队列和消息循环. 工作者线程没有消息机制,通 ...

  4. MFC多线程内存泄漏问题&amp;解决方法

    在用visual studio进行界面编程时(如MFC),前台UI我们能够通过MFC的消息循环机制实现.而对于后台的数据处理.我们可能会用到多线程来处理. 那么对于大多数人(尤其是我这样的菜鸟),一个 ...

  5. [转] iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用

    介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统.这建立在任务并行执行的线程池模式的基础上的.它首 ...

  6. [转] iOS多线程编程之NSOperation和NSOperationQueue的使用

    <iOS多线程编程之NSThread的使用> 介绍三种多线程编程和NSThread的使用,这篇介绍NSOperation的使用. 使用 NSOperation的方式有两种, 一种是用定义好 ...

  7. [转]iOS多线程编程之NSThread的使用

    1.简介: 1.1 iOS有三种多线程编程的技术,分别是: 1..NSThread 2.Cocoa NSOperation (iOS多线程编程之NSOperation和NSOperationQueue ...

  8. iOS 多线程编程之Grand Central Dispatch(GCD)

    介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其它的对称多处理系统的系统.这建立在任务并行运行的线程池模式的基础上的. 它 ...

  9. MFC多线程各种线程用法 .

    http://blog.csdn.net/qq61394323/article/details/9328301 一.问题的提出 编写一个耗时的单线程程序: 新建一个基于对话框的应用程序SingleTh ...

随机推荐

  1. CREATE DATABASE

    CREATE DATABASE IF NOT EXISTS `focusdata` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;USE `fo ...

  2. php 获取网站根目录的写法

    路径方式,代码如下: define('BASE_PATH',str_replace('\\','/',realpath(dirname(__FILE__).'/'))."/"); ...

  3. xcode5.1上真机调试报告No architectures to compile for...的解决办法

    由于手头上只有一台IPAD一代,近期升级到IOS5.0了(人家apple只让升级到此为止)而开发环境Xcode版本是5.1,默认情况下XCode编译出来的代码最低能跑在IOS6.0下, 于是GOOGL ...

  4. iOS学习之自定义UItableViewCell

    在项目开发中,大部分情况下我们都需要自定义UITableViewCell, 今天就重点整理一下目前自己已经学过的自定义Cell的一些注意事项; 分步骤来写吧: 1.将自定义的Cell定义为属性; 2. ...

  5. Java学习笔记--PriorityQueue(优先队列)(堆)

    PriorityQueue(优先队列)实际上是一个堆(不指定Comparator时默认为最小堆)队列既可以根据元素的自然顺序来排序,也可以根据 Comparator来设置排序规则.队列的头是按指定排序 ...

  6. java属性文件读取,属性修改

    /** * 属性文件读取 * @author bestmata * */ public class CommUtil { private static Logger logger=Logger.get ...

  7. 深入浅出Node.js (7) - 网络编程

    7.1 构建TCP服务 7.1.1 TCP 7.1.2 创建TCP服务器端 7.1.3 TCP服务的事件 7.2 构建UDP服务 7.2.1 创建UDP套接字 7.2.2 创建UDP服务器端 7.2. ...

  8. 【转】Android开源项目发现---ListView篇(持续更新)

    原文网址:http://blog.csdn.net/krislight/article/details/20211045 资料转载地址:https://github.com/Trinea/androi ...

  9. 黑马程序员_Java基本数据类型对象包装类

    基本数据类型对象包装类 byte Byte short Short int Integer long Long boolean Boolean float Float double Double ch ...

  10. cf445A DZY Loves Chessboard

    A. DZY Loves Chessboard time limit per test 1 second memory limit per test 256 megabytes input stand ...