線程中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


發佈了43 篇原創文章 · 獲贊 12 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章