【问题标题】:Control.Invoke getting 'stuck' in hidden ShowDialogControl.Invoke 在隐藏的 ShowDialog 中“卡住”
【发布时间】:2010-01-13 10:33:23
【问题描述】:

(我有一个解决这个问题的方法,但这不是我第一次被咬,所以我想弄清楚到底发生了什么。)

  • 从我的申请中,我ShowDialog 一个表格。
  • 表单上有一个按钮,单击该按钮会调用另一个(非 GUI)线程上的代码。
  • 非 GUI 线程通过 Control.Invoke 发回状态(Pushed 然后Released
  • 当表单看到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 替换为Show,问题就会消失,但有趣的是,它会变得更好(发生的频率降低),但如果我注释掉执行Hide 的代码,问题不会完全消失Pushed.

更新

感谢nobugz,我发现了死锁(我以前只在数据库中遇到过)!显然用 Control.BeginInvoke 替换 Control.Invoke 解决了这个问题(状态事件有时仍然会“卡住”,但它不会阻止所有后续通信)。

【问题讨论】:

    标签: c# .net multithreading invoke


    【解决方案1】:

    要处理Control.Invoke() 调用,GUI 线程必须发送一条Windows 消息,但ShowDialog() 是一个阻塞调用,因此在ShowDialog() 返回之前它不能这样做。

    Control.Invoke() 也是阻塞的,调用它的线程必须等到 GUI 线程接收到消息并处理它才能继续。如果包含Control.Invoke() 的代码可以关闭对话框,那么bingo,就会出现死锁。

    这有点棘手,因为像 SosEx 的 dlk 命令这样的死锁检测器无法从转储或 WinDgb 会话中检测到问题 - GUI 线程处理 Control.Invoke() 所涉及的“锁定”是“隐含的” ,而不是实际的WaitHandle

    【讨论】:

      【解决方案2】:

      显然,您正在与僵局作斗争。当您使用 Control.Invoke() 而不是 BeginInvoke() 时,这总是指日可待。我不清楚是什么使您的帖子陷入僵局。一个危险信号是在使用 ShowDialog() 显示的表单上使用 Hide()。这通常会关闭对话框。

      最好的办法是调试它。等到死锁发生,然后使用 Debug + Break All。使用 Debug + Windows + Threads 并切换到 UI 线程。查看调用堆栈。如果它没有泵送消息循环 (Application.Run()) 但卡在某处(如您似乎正在使用的等待句柄),则结果是死锁。

      【讨论】:

      • 是的,我正在尝试回收表单。话虽如此,关闭它,或者只是设置DialogResult,仍然具有相同的效果。现在我需要去阅读一下 Invoke 和 BeginInvoke 之间的区别......
      【解决方案3】:

      我只是遇到了我认为是这样的。

      从一个 GUI 线程调用另一个 GUI 线程,并让该线程执行 ShowDialog。如果用户的 GUI 偏好改变(例如背景旋转器),死锁。

      【讨论】:

        猜你喜欢
        • 2013-02-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-05
        • 1970-01-01
        相关资源
        最近更新 更多