2010-09-21 139 views
11

当我从工作线程调用UI线程时,发生死锁。事实上,工作线程被阻塞在调用行:从工作线程调用UI线程时发生死锁

return (ucAvancementTrtFamille)mInterfaceTraitement.Invoke(d, new object[] { psFamille }); 

奇怪的是,在UI线程(其中,纠正我,如果我错了,是主线程)处于闲置状态。

有没有什么办法:

  1. 看到哪个线程实际上,我试图调用?
  2. 看看线程真的在干什么?

我们可以在下图中看到工作线程(ID 3732)在Invoke行上被阻塞,并且MainThread在应用程序的主函数中处于空闲状态。

alt text

编辑:这是主线程的堆栈:

alt text

EDIT2:其实,我暂停了该计划第二次,这里是堆栈的样子:

alt text

EDIT3:发现解决方法

我终于找到了解决方法。问题显然是由于异步包装竞赛 条件问题。解决方法是使用BeginInvoke并等待它超时。当它超时时,再次调用并循环直到它最终返回。大多数情况下,它实际上是在第二个电话上工作。

IAsyncResult ar = mInterfaceTraitement.BeginInvoke(d, new object[] { psFamille }); 
      while (!ar.AsyncWaitHandle.WaitOne(3000, false)) 
      { 
       ar = mInterfaceTraitement.BeginInvoke(d, new object[] { psFamille }); 
      } 
      // Async call has returned - get response 
      ucAvancementTrtFamille mucAvancementTrtFamille = (ucAvancementTrtFamille)mInterfaceTraitement.EndInvoke(ar); 

这不是很漂亮,但它是我发现的唯一解决方案。

+0

你可以发布'd'委托人在做什么吗? – 2010-09-21 17:46:14

+0

这是一个WinForms或WPF应用程序,对吧? – 2010-09-21 17:48:27

+0

委托只是创建一个图形控件(在这一点上它甚至不会将它添加到任何形式)。我使用WinForms。 – leo 2010-09-22 07:46:37

回答

5

主线程不显示空闲。您的屏幕截图显示了它在ECM.Program.Main上的当前位置。这是不正确的,如果它是空闲的,那么它在Application.Run()中,抽取消息循环。这是Invoke()完成所需的。

双击主线程并切换到“调用堆栈”窗口,以查明它真的在做什么。

+0

嗯,你是对的:它在我的ECM.Program.Main中的Application.Run()中。看我的编辑:它显示主线程的堆栈。 – leo 2010-09-22 07:33:34

+0

是的,看起来它也是抽向我。粗。设置Symbol Server,启用非托管代码调试并向我们显示死锁线程的调用堆栈。 – 2010-09-22 12:02:29

+0

看来,异步包装有一个竞争条件问题。使用我找到的解决方法查看我的第三个编辑。 – leo 2010-09-23 09:09:45

2

您是否尝试过使用BeginInvoke而不是InvokeBeginInvoke是异步的。

+0

但调用应该工作 – Andrey 2010-09-21 16:56:30

+0

是的,但是'BeginInvoke'不会阻塞调用者。这只是一个建议,虽然是的,这应该不重要。 – 2010-09-21 16:58:31

+1

SimpleCoder,OP想要从Invoke返回值。 BeginInvoke不能代替这里。 – 2010-09-21 17:47:13

0

您是否尝试过使用BackgroundWorker来代替。如果你使用它,它会为你节省很多这种Invoke和InvokeRequired调用。
我相信如果你创建一个新的线程并让它执行你所显示的那一行,你就不会有死锁。我会尝试找到我的旧代码并将其发布在此处。

2

你是对的。主线程是应用程序的入口点,通常是Application.Run的调用位置,它将使消息循环继续。所以这应该是UI线程,除非你在消息循环方面做了不寻常的事情。

在线程窗口中,您可以右键单击主线程,然后选择切换以将调试上下文更改为该线程。 Call Stack窗口将显示当前执行方法的位置。

如果您的工作线程真的在Control.Invoke调用上被阻塞,并且UI线程处于空闲状态,那么您可能会遇到问题可能是由于正在封送的代理或消息循环中的指令执行尚未完成开始。后面看起来貌似合理,因为你的屏幕显示主线程的位置为Main

+0

我正在编辑我的问题,并添加主线程的堆栈。我已启用“显示外部代码”选项。 – leo 2010-09-22 07:36:23

0

您是否使用Visual Studio 2008? 如果答案是肯定的,你应该尝试使用Visual Studio 2010.这是一个已知的错误。

祝你好运!