从工作线程调用 UI 线程时出现死锁

发布于 2024-09-24 01:24:05 字数 1272 浏览 1 评论 0原文

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

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

奇怪的是 UI 线程(如果我错了,请纠正我,它是主线程)处于空闲状态。

有没有办法:

  1. 查看我实际上正在尝试调用哪个线程?
  2. 看看所说的线程到底在做什么?

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

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);

它并不漂亮,但这是我找到的唯一解决方案。

I have a deadlock when I invoke the UI thread from a worker thread. Indeed, the worker thread is blocked on the invoke line:

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

The weird thing is that the UI Thread (which, correct me if I'm wrong, is the main thread) is idle.

Is there any way to:

  1. see which thread I'm actually trying to invoke?
  2. see what said thread is really doing?

We can see in the image below, the worker thread (ID 3732) blocked on the Invoke line, and the MainThread is idle in the main function of the application.

alt text

Edit: Here is the stack of the main thread:

alt text

Edit2: Actually, I paused the the program a second time, and here is what the stack looks like:

alt text

Edit3: Workaround found

I finally found a workaround. The problem is apparently due to an async wrapper race
condition issue. The workaround is to use BeginInvoke and wait for it with a timeout. When it times out, invoke it again and loop until it finally returns. Most of the time, it actually works on the second call.

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);

It's not pretty but it's the only solution I found.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

怪我入戏太深 2024-10-01 01:24:05

主线程看起来并不空闲。您的屏幕截图显示了它的当前位置:ECM.Program.Main。这是不正确的,如果它空闲,那么它在 Application.Run() 内部,泵送消息循环。这是 Invoke() 完成所必需的。

双击主线程并切换到“调用堆栈”窗口以了解它到底在做什么。

The Main thread doesn't look idle. Your screen shot shows it current location at ECM.Program.Main. That can't be correct, if it is idle then it is inside Application.Run(), pumping the message loop. Which is required for Invoke() to complete.

Double-click the main thread and switch to the Call Stack window to find out what it is really doing.

离去的眼神 2024-10-01 01:24:05

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

Have you tried using BeginInvoke instead of Invoke? BeginInvoke is asynchronous.

烟凡古楼 2024-10-01 01:24:05

你是对的。主线程是应用程序的入口点,通常是调用 Application.Run 的位置,该调用使消息循环继续运行。因此,这应该是 UI 线程,除非您对消息循环做了一些不寻常的事情,而这种情况不太可能发生。

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

如果您的工作线程确实在 Control.Invoke 调用上被阻塞,并且 UI 线程如您所说处于空闲状态,那么问题可能出在正在编组的委托或消息中的指令的执行上循环尚未开始。后者似乎是合理的,因为您的屏幕将主线程的位置显示为 Main

You are correct. The Main Thread is the entry point to the application which is normally the location of the call to Application.Run which gets the message loop going. So that should be the UI thread unless you have done something out of the ordinary in regards to the message loop which is unlikely.

In the Thread window you can right click on the Main Thread and select Switch to change the debugging context to that thread. The Call Stack window will then show the location of the current executing method.

If your worker thread really is blocked on the Control.Invoke call and the UI thread is idle as you claim then the problem could be with the execution of the instructions within the delegate that is being marshaled or the message loop as not yet been started. The later seems plausible since your screen shows the location of the Main Thread as Main.

蓝色星空 2024-10-01 01:24:05

您是否尝试过使用BackgroundWorker 来代替。如果您使用它,它将为您节省大量的 this.Invoke 和 InvokeRequired 调用。
我相信,如果您创建一个新线程并使其执行您所显示的行,则不会出现死锁。我会尝试找到我的旧代码并将其发布在这里。

Have you tried using a BackgroundWorker instead. If you use it it will save you a lot of this.Invoke and InvokeRequired calls.
I believe that if you create a new thread and make it execute the line you are showing you won't have a deadlock. I will try find old code of mine and post it here.

迎风吟唱 2024-10-01 01:24:05

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

祝你好运 !

Are you using Visual Studio 2008 ?
If the answer is yes, you should try with Visual Studio 2010. It's a known bug.

Good luck !

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文