行情報價關閉K線界面卡死
前奏
- Dump收集
- Clr運行時檔案收集
- 收集檔案放到同一目錄,VS打開
- 查看執行緒堆疊
問題還原
- 主執行緒停在Messenger.UnregsiterCore處(關閉K線界面,呼叫VM的CleanUp方法引起)
- 作業執行緒1停在Messenger.Send處
- 作業執行緒2停在Forms.Control.WaitForWaitHandle處(堆疊上游是Messenger.Send后執行注冊的方法)
問題分析
- 上面的作業執行緒2的堆疊是一個常見的客戶端死鎖現象,一般由Control.Invoke呼叫,等待主執行緒操作權限
- 接下來看主執行緒現在在干什么,主執行緒在執行Messenger的取消注冊方法
- 作業執行緒1也在執行Messenger的發送方法
- 查看Messenger原始碼,發現里面只有私有變數
isMultiThreadSafe為true時,才會進入鎖物件actionInvoker,而一般的Messenger.Default實體的該變數值為false - 通過定位,Messenger.Default是我們自己賦的值,同時傳參true,即
isMultiThreadSafe=true - 問題原因昭然若揭,作業執行緒2通過Send方法獲取了鎖
actionInvoker,并執行Send事件對應的方法,方法內部呼叫Control.Invoke等待主執行緒回應,但此時主執行緒正在CleanUpK線的vm,同時取消Messenger的訂閱,這個取消訂閱需要等待鎖actionInvoker被釋放,這個鎖actionInvoker被作業執行緒2占用,執行緒2在等主執行緒,主執行緒在等鎖actionInvoker……死鎖,
解決方法
- 作業執行緒2的Control.Invoke呼叫,換成Control.BeginInvoke
- Messenger.Send方法是同步執行被注冊方法的,導致方法沒有執行完成時,鎖一直被占用,我們可以添加一個IMessenger的Post擴展方法,在執行緒池上執行被注冊方法,同時鎖被立即釋放,死鎖環也可以解開,
注:以上的Messenger為DevExpress的一個訊息類
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/257617.html
標籤:C#
