Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 控件。调用获取';卡住';在隐藏的ShowDialog中_C#_.net_Multithreading_Invoke - Fatal编程技术网

C# 控件。调用获取';卡住';在隐藏的ShowDialog中

C# 控件。调用获取';卡住';在隐藏的ShowDialog中,c#,.net,multithreading,invoke,C#,.net,Multithreading,Invoke,(我有一个解决这个问题的方法,但这不是我第一次被咬,所以我正试图确切地了解到底发生了什么。) 从我的应用程序中,我ShowDialoga表单 表单上有一个按钮,单击该按钮可调用另一个(非Gui)线程上的代码 非GUI线程通过控件返回状态(push然后Released) 当表单看到推送的时,它调用表单.Hide() 当表单看到发布的时,它会更改按钮的外观 发生的情况是,有时,但不是每次,非Gui线程在试图发送发布的时“卡住”。没有例外,Gui将继续“工作”,但不可能在任何方向与非Gui线程进行

(我有一个解决这个问题的方法,但这不是我第一次被咬,所以我正试图确切地了解到底发生了什么。)

  • 从我的应用程序中,我
    ShowDialog
    a表单
  • 表单上有一个按钮,单击该按钮可调用另一个(非Gui)线程上的代码
  • 非GUI线程通过控件返回状态(
    push
    然后
    Released
  • 当表单看到推送的
    时,它调用
    表单.Hide()
  • 当表单看到发布的
    时,它会更改按钮的外观
发生的情况是,有时,但不是每次,非Gui线程在试图发送发布的
时“卡住”。没有例外,Gui将继续“工作”,但不可能在任何方向与非Gui线程进行进一步通信

线程的(简化的)调用堆栈如下所示:

System.Threading.WaitHandle.WaitOne()
(...)
System.Windows.Forms.Control.WaitForWaitHandle()
(...)
System.Windows.Forms.Control.Invoke()
(...)
GuiCode.OnStatusChanged()
(...)
NonGuiCode.SetStatus()
如果我将
ShowDialog
替换为
Show
,问题就会消失,但有趣的是,它会变得更好(发生的次数更少),但如果我注释掉在
上执行
隐藏的
代码,问题就不会完全消失

更新


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

显然,您正在与死锁作斗争。当您使用Control.Invoke()而不是BeginInvoke()时,这一点总是很容易实现的。我不清楚是什么打破了你帖子中的僵局。一个红色标志是在使用ShowDialog()显示的窗体上使用Hide()。这通常会关闭对话框


最好的办法是调试它。等待死锁发生,然后使用Debug+Break All。使用Debug+Windows+线程并切换到UI线程。看看调用堆栈。如果它不是在泵送消息循环(Application.Run()),而是被卡在某个地方(如您似乎正在使用的等待句柄),则会导致死锁。

我刚刚遇到了我认为是这样的情况


从一个GUI线程调用另一个GUI线程,并让该线程执行ShowDialog。如果用户的GUI首选项发生更改(例如后台旋转器),则会死锁。

要处理
控件.Invoke()
调用,GUI线程必须发送Windows消息,但是
ShowDialog()
是一个阻塞调用,因此在
ShowDialog()
返回之前,它无法执行此操作

Control.Invoke()
也在阻塞,调用它的线程必须等待GUI线程拾取消息并处理它才能继续。如果包含
控件.Invoke()
的代码允许取消对话框,那么宾果操作,就会出现死锁


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

是的,我正在尝试回收表单。尽管如此,关闭它,或者只是设置DialogResult,仍然具有相同的效果。现在我需要去读一下Invoke和BeginInvoke之间的区别。。。