(我有解决这个问题的方法,但这不是我第一次被咬,所以我试图确切地了解发生了什么。)
- 从我的申请中,我
ShowDialog
表单。
- 表单上有一个按钮,单击该按钮时会调用另一个(非 GUI)线程上的代码。
- 非 GUI 线程发回状态 (
Pushed
then Released
) 通过 Control.Invoke
- 当表格看到
Pushed
,它调用form.Hide()
- 当表格看到
Released
,它会更改按钮的外观。
发生的情况是,有时(但并非每次)非 Gui 线程在尝试发送Released
。无一例外,Gui 继续“工作”,但无论在哪个方向,都不可能与非 Gui 线程进行进一步的通信。
线程的(简化的)调用堆栈如下所示:
System.Threading.WaitHandle.WaitOne()
(...)
System.Windows.Forms.Control.WaitForWaitHandle()
(...)
System.Windows.Forms.Control.Invoke()
(...)
GuiCode.OnStatusChanged()
(...)
NonGuiCode.SetStatus()
如果我更换,问题就会消失ShowDialog
with Show
,但是 - 有趣的是 - 它会变得更好(发生得更少),但如果我注释掉执行以下操作的代码,它不会完全消失Hide
on Pushed
.
Update
谢谢nobugz https://stackoverflow.com/questions/2055960/control-invoke-getting-stuck-in-hidden-showdialog/2056427#2056427,我发现了死锁(我以前只在数据库中遇到过)!显然,用 Control.BeginInvoke 替换 Control.Invoke 可以解决此问题(状态事件有时仍然“卡住”,但它不会阻止所有后续通信)。
为了处理Control.Invoke()
调用时,GUI 线程必须发送 Windows 消息,但是ShowDialog()
是一个阻塞调用,所以它不能这样做,直到ShowDialog()
返回。
Control.Invoke()
也是阻塞的,调用它的线程必须等待,直到 GUI 线程拾取消息并处理它才能继续。如果代码包含Control.Invoke()
是什么使得对话框消失,然后bingo,这就是你的僵局。
这有点棘手,因为像 SosEx 这样的死锁检测器dlk
命令无法从转储或 WinDgb 会话中检测到问题 - GUI 线程处理中涉及的“锁”Control.Invoke()
是“隐含的”,而不是实际的WaitHandle
.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)