UI僵死無非只是由於UI線程因繁忙而沒法去接受用戶的響應。詳細說來內在緣由有如下兩個:html
PostMessagewindows
- 將消息送至目標window所在線程(可經過系統API獲取控件的句柄所屬的線程)的「Posted Message Queue」消息隊列,消息稱爲列隊型(queued)型消息
- Control.Invoke與Control.BeginInvoke都調用PostMessage(相比SendMessage可防止死鎖),區別是前者會使用WaitForWaitHandle來等待消息處理完畢
SendMessageapi
- 將消息送至目標window所在線程的「Sent Message Queue」消息隊列,但消息稱爲非列隊型(Non-queued)消息
- 發送線程調用SendMessage後會掛起並等待返回,若是期間有其餘線程發消息給這個發送線程,它能夠響應,但僅限於非隊列型(Non-queued)消息
- WH_CALLWNDPROC鉤子用於監視SendMessage調用
診斷的目的是要肯定引起了UI線程繁忙的緣由。安全
防患於未然數據結構
寫代碼時應該遵循這條原則:保證線程安全,尤爲是不應在非UI線程上直接進行UI操做,包括控件的建立。app
不過團隊水平良莠不齊,即便是一些老手也不免犯錯。函數
因此若是可以攔截控件建立的過程,那麼就能夠經過Windows API根據此控件的句柄獲取其在運行的線程號,看是否就是主UI線程號來輸出日誌,以在調試階段解決問題。工具
有如下兩種途徑:ui
攔截Winodws Message。經過建立Global Hook攔截全部線程的窗口建立消息。spa
攔截Windows API。經過攔截各線程對窗口建立的API的調用。
使用windbg拉截windows api的調用前不要忘了爲其加載符號。如:srv*c:\symbols*http://msdl.microsoft.com/download/symbols
本人經過EasyHook開源庫使用了第2種方法,即攔截對WindowsAPI的調用完成了工具的建立,截圖以下:
參考
Debugging Windows Forms Application Hangs During SystemEvents.UserPreferenceChanged
Windows Forms application freezes when system settings are changed or the workstation is locked
Mysterious Hang or The Great Deception of InvokeRequired
WinForm二三事(三)Control.Invoke&Control.BeginInvoke
一千個是什麼 - Windows消息機制(Windows Messaging)
Using Window Messages to Implement Global System Hooks in C#
Windows下Hook API技術 inline hook