死锁使用Control.Invoke?(Deadlock using Control.Invoke?

2019-10-16 17:09发布

我建设VS2010旗舰版使用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几个电话。

视图是内部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>

任何帮助将不胜感激。

Answer 1:

没错,你有一个僵局。 什么Parallel.ForEach()的作用是,它使用一个或多个线程包括当前 ,然后阻止当前线程,直到所有的迭代完成运行迭代。

这意味着,如果你调用DoRepresentation()从UI线程,你会得到一个僵局:UI线程正在等待其他线程的迭代来完成,而其他线程都在等待Invoke()来完成,这是不可能发生的如果UI线程被阻塞。

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

我不明白,究竟是什么做的(好像它覆盖的代码representation在每次迭代中),但我想你应该运行ForEach()从后台线程。 这意味着DoRepresentation()将完成其工作,因此之前返回Invoke()将正常工作。

在一般情况下,它不阻塞很长一段时间的UI线程是一个好主意,所以你应该运行在另一个线程的费时码。



Answer 2:

您可以使用调用方法的BeginInvoke的insteed。 如果你还需要,那么你可以锁定对象,并确保直到意识到这将无法访问来自其他线程。

使用开始调用方法

void UpdateRepresentation(object g)
{
  view.BeginInvoke( new Action(() =>
  {
    representation = new MyRepresentation(g);
  }));
}

使用锁

void UpdateRepresentation(object g)
{
lock(this) 
{
 view.Invoke(new Action(() =>
  {
    representation = new MyRepresentation(g);
  }));
}

}


Answer 3:

该意见适用于我的具体应用程序,这是在C#一个Windows应用程序:使用锁对我也没有工作,并且应用程序只是冻结了。 BeginInvoke工作,但我不喜欢有UI控件异步更新的效果。

我结束了在开始主过程作为一个单独的线程( System.Threading.Tasks.Task ),这将启动,并立即给我回主线程的控制。 然后,在等待其他几个任务在一个循环结束执行,我也结束了具有插入此行: System.Windows.Forms.Application.DoEvents()以使系统能够处理在队列中等待的所有消息。 现在,它的工作适合我的申请。 有可能是另一种方法对皮肤这只猫,但现在的工作。



文章来源: Deadlock using Control.Invoke?