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