Skip to main content
 首页 » 编程设计

c#之使用 Control.Invoke 的死锁

2024年01月22日27yyy_WW

我正在 VS2010 Ultimate 中使用 TPL 构建应用程序。大多数情况下,当我从 UI 线程调用 DoRepresentation() 时,我运行应用程序时它变得无响应。

void DoRepresentation() 
{ 
  Parallel.ForEach(cgs, loopOptions, g => 
  { 
    UpdateRepresentation(g); 
  }); 
} 
 
void UpdateRepresentation(object g) 
{ 
  view.Invoke(new Action(() => 
  { 
    representation = new MyRepresentation(g); 
  })); 
} 

我不知道为什么该应用变得无响应。我遇到了僵局吗?

在 MyRepresentation 中,我对 OpenGL 进行了一些调用。

view 是 Form1(主窗体)内的控件。

当应用程序变得无响应时,我从 VS IDE 暂停它,这是我得到的信息

在“并行任务”窗口中,我得到以下信息:

ID  Status       Message<br> 
1    ?Waiting   Task1 is waiting on object: "Task2"<br> 
2    ?Waiting   No waiting information available<br> 

在“调用堆栈”窗口中,我得到以下信息:

[In a Sleep, wait, or join]<br> 
[External Code]<br> 
Test.dll!Render.DoRepresentation()<br> 
App1.exe!Form1.Button1_Click<br> 

我们将不胜感激。

请您参考如下方法:

是的,你遇到了僵局。 Parallel.ForEach() 的作用是使用一个或多个线程包括当前线程运行迭代,然后阻塞当前线程,直到所有迭代完成。 p>

这意味着如果您从 UI 线程调用 DoRepresentation(),就会出现死锁:UI 线程正在等待其他线程上的迭代完成,而其他线程正在等待 Invoke() 完成,如果 UI 线程被阻塞,则不会发生这种情况。

此外,在您的情况下,使用 Parallel.ForEach() 没有任何意义(假设这是您的实际代码):您运行 new MyRepresentation()在 UI 线程上。

我不明白代码到底在做什么(它似乎在每次迭代中都覆盖了 representation),但我认为你应该运行 ForEach()后台线程。这意味着 DoRepresentation() 将在完成其工作之前返回,因此 Invoke() 将正常工作。

一般而言,长时间阻塞 UI 线程并不是一个好主意,因此您应该在另一个线程上运行任何耗时的代码。