在WinForms中使用WPF:尽管UI线程存活,但在Dispatcher.Invoke上被阻止。

4
我们有一个嵌入在WinForms控件中的WPF控件,该控件最终作为ActiveX控件在第三方开发的C++应用程序中使用。但是,在某些情况下,ActiveX控件的UI会冻结,而C++应用程序的其余部分则正常运行。经过调试,发现在每次调用Application.Current.Dispatcher.Invoke时,WPF控件都会被阻塞,然而WinForms控件能够处理Control.Invoke的调用。每当我暂停调试器时,都可以看到UI线程正在C++应用程序中执行一些工作,但似乎没有被阻塞或等待任何内容。就好像UI线程突然无法执行WPF代理一样。
当C++应用程序长时间独占UI线程(几分钟)时,WPF控件有时会进入此状态。虽然我不负责C++应用程序所做的事情,但第一件事应该是为这样的耗时任务使用不同的线程。无论如何,这并不是导致WPF控件表现出这种方式的原因。我不知道如何解决这个问题,希望得到帮助。
2个回答

1
我建议运行MS Debug诊断工具-http://support.microsoft.com/kb/2580960
我们使用它来识别COM互操作阻塞问题,取得了很好的效果,在我们的情况下是由于挂起的COM终结器阻塞了垃圾回收。您可以以各种模式运行它,但是当使用.NET分析运行时,它将突出显示任何与终结器队列等有关的问题。它运行起来有点笨重,但它提供的信息是非常宝贵的。

0

Invoke 的问题在于它的行为类似于多线程调用,但实际上并不是。 Invoke 是阻塞的,仍然只允许一个线程运行。 Invoke 真正做的只是确保在 UI 线程上执行某个操作。这是通过将消息强制插入消息队列并以此方式执行来完成的。该操作可能会被阻塞在调用 Invoke 的线程需要执行的某些操作上,以便让该操作继续进行。

lock(someLock)
{
    dispatcher.Invoke(SomeMethod);
}

//...

public void SomeMethod()
{
  lock(someLock)
  {
  //... do some work here
  }
}

在这个例子中,当持有锁时,Invoke 被阻塞调用 SomeMethod。但是,SomeMethod 需要相同的 lock,因此它被阻塞等待该 lock。你遇到了死锁。
我建议使用 BeginInvoke
我不确定这是否是你的问题,因为你没有提供任何代码;但这是 Invoke 的一个非常普遍的问题。通常没有必要使用 Invoke;如果你认为需要使用,那通常是存在问题的迹象。

谢谢你的回答,彼得。在你的例子中,主线程将被锁定在SomeMethod中的锁上。而在我的情况下,它没有被任何东西阻塞;我真的没有理由被卡在Invoke上。正如我所说,WinForm中同一线程中的Invokes工作得很好。显然是WPF Dispatcher出了问题,不再响应。 - Odsh
@odsh 是的,那只是一个例子,说明你在使用Invoke而不是BeginInvoke时可能会遇到死锁问题——尽管这是针对WinForms而非WPF的。Dispatcher.Invoke/BeginInvoke同样适用。框架方法在许多你无法控制的地方进行了锁定,导致类似的情况。你试过使用Dispatcher.BeginInvoke吗? - Peter Ritchie
我无法负担替换应用程序中所有的Invokes为BeginInvokes; 有时调用必须是同步的。无论如何,我不认为存在死锁,否则主线程将被阻塞-但实际上并没有发生。如果像您建议的那样,某个框架方法在某处被阻塞,我想了解原因并纠正问题。在我这种情况下,丢弃Invokes因为它们可能会在我不知道的地方随机引起死锁不是一个解决方案。 - Odsh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接