当我从工作线程调用UI线程时,我遇到了死锁。实际上,工作线程在调用行上被阻止:
return (ucAvancementTrtFamille)mInterfaceTraitement.Invoke(d, new object[] { psFamille });
奇怪的是UI线程(如果我错了,纠正我是主线程)是空闲的。
有没有办法:
我们可以在下图中看到,工作线程(ID 3732)在Invoke行上被阻塞,MainThread在应用程序的main函数中处于空闲状态。
编辑:这是主线程的堆栈:
Edit2:实际上,我第二次暂停了程序,这就是堆栈的样子:
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 :(得分:5)
主线程看起来并不空闲。您的屏幕截图显示它在ECM.Program.Main的当前位置。这可能是不正确的,如果它是空闲的,那么它在Application.Run()内,抽取消息循环。这是Invoke()完成所必需的。
双击主线程并切换到“调用堆栈”窗口以查明它实际执行的操作。
答案 1 :(得分:2)
您是否尝试过使用BeginInvoke
代替Invoke
? BeginInvoke
是异步的。
答案 2 :(得分:2)
你是对的。主线程是应用程序的入口点,通常是调用Application.Run
的位置,它会使消息循环进入。所以这应该是UI线程,除非你在消息循环方面做了一些与众不同的事情,这是不可能的。
在Thread窗口中,您可以右键单击Main Thread并选择Switch以将调试上下文更改为该线程。然后,“调用堆栈”窗口将显示当前执行方法的位置。
如果您的工作线程确实在Control.Invoke
调用中被阻止且UI线程处于空闲状态,那么问题可能在于正在编组的代理中的指令执行或消息循环为尚未开始。后者似乎有道理,因为您的屏幕显示主线程的位置为Main
。
答案 3 :(得分:0)
您是否尝试过使用BackgroundWorker?如果你使用它,它将为你节省很多.Invoke和InvokeRequired调用。
我相信如果你创建一个新线程并让它执行你显示的行,你将不会有死锁。我会尝试找到我的旧代码并在此处发布。
答案 4 :(得分:0)
您使用的是Visual Studio 2008吗? 如果答案是肯定的,那么您应该尝试使用Visual Studio 2010.这是一个已知的错误。
祝你好运!