线程中WaitCommEvent使用临时栈区变量导致Release版本崩溃

问题:

使用一个串口类进行串口收发,由于只是调试,所以并没有真实的数据能被接收,所以原来的程序问题多多。

1、没有接收到数据就死循环等待。

2、执行三四个模块(共有18个相似的模块,每个模块发送一帧数据,然后立即接收一帧数据)即崩溃。

但是在调试版本中运行正常。

过程:

第一个问题好解决,等待一定时间(使用一个较大的计数),如果超过一定时间没有收到,则退出(当然,以后可能会有隐患)。

第二个问题不好解决,因为表现并不明显,刚开始也没有锁定是串口收发出现问题。

  先是怀疑MFC的DDX_Control太多出现无法预测的问题,未果。

  后又怀疑线程同步有问题,使用全局变量进行同步,未果。

  大量使用Release崩溃地址进行查找也未果。

  后来才发现屏蔽掉串口接收函数就可以成功,于是赶快逐行测试,最后发现只要屏蔽掉WaitCommEvent函数就可以成功。

打开MSDN,发现并没有关于这方面的说明。所以只好怀疑是传进去的变量出了问题。经检查发现OVERLAPPED变量都是临时栈区变量,进行AfxMessageBox显示后,发现崩溃前各个变量地址相同,后来地址出现偏移(向前偏移了12个字节),接着就崩溃了。

  于是,将临时栈区变量改为类成员变量,测试后可以通过并成功运行。

总结:

  多线程会带来诸多问题:

  1、MFC类对象不是线程安全的,所以不定在什么情况下会崩溃。

       a、 mfc的大多数类不是线程安全的,cwnd及其消息路由是其中之最

       b、 mfc界面类的大多数方法,最后都是通过sendmessage实现的,而消息处理的  

        过程中会引发其他消息的发送及处理。如果消息处理函数本身不是线程安全的   
        你从工作线程中调用这些方法迟早会同你界面线程的用户消息响应发生冲突  
       c、cxxxx::fromhandle会根据调用者所在线程查表,如果查不到用户创建的cxxxx  
        对应对象,它会创建一个临时对象出来。由于你在工作线程中调用该方法,当然   
        不可能查到界面主线程中你所建立起来的那个对象了。这时 mfc 会你创建一个临时   
        对象并返回给你,你根本不可能期望它的成员变量会是有意义的。    所以要用   
        也只能用 cwnd::fromhandle ,因为它只包含一个 m_hwnd 成员。    不过,要记住   
        跨线程直接或间接地调用 ::sendmessage, 通常都是行为不可预测的。
  2、DDX_Control不能大量使用,否则也会引起不必要的问题。

  3、启动线程时传输窗口对象(指针?句柄?)容易出现问题。

  4、主程序突然退出时容易出现子线程引用对象析构导致崩溃问题。

  5、MFC界面包装类(多线程时成员函数调用的断言失败)。

  6、也就是说一个线程不可以也不应该访问另一个线程中的包装类对象

其它参考资料:

MFC多线程编程注意事项http://blog.csdn.net/sunshine1314/article/details/2481602


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值