C# 使用Control.Invoke实现死锁?

C# 使用Control.Invoke实现死锁?,c#,winforms,task-parallel-library,C#,Winforms,Task Parallel Library,我正在VS2010 Ultimate中使用TPL构建一个应用程序。运行应用程序的大多数时候,当我从UI线程调用DoRepresentation()时,它会变得无响应 void DoRepresentation() { Parallel.ForEach(cgs, loopOptions, g => { UpdateRepresentation(g); }); } void UpdateRepresentation(object g) { view.Invoke(ne

我正在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进行了一些调用

视图是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>
ID状态消息
1?等待任务1正在等待对象:“任务2”
2?等待没有可用的等待信息
在“调用堆栈”窗口中,我得到以下信息:

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>
[处于睡眠、等待或加入状态]
[外部代码]
Test.dll!Render.DoRepresentation()
App1.exe!表单1.按钮1\u单击

任何帮助都将不胜感激。

您可以使用BeginInvoke而不是Invoke方法。如果您仍然需要,那么您可以锁定一个对象,并确保在其实现之前无法从另一个线程访问该对象

使用begininvoke方法

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

}

您可以使用BeginInvoke而不是Invoke方法。如果您仍然需要,那么您可以锁定一个对象,并确保在其实现之前无法从另一个线程访问该对象

使用begininvoke方法

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

}

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

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

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

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


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

是的,您遇到了死锁。
Parallel.ForEach()
所做的是,它使用一个或多个线程(包括当前线程)运行迭代,然后阻塞当前线程,直到所有迭代完成

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

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

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


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

此评论适用于我的特定应用程序,它是C#中的Windows应用程序:使用锁对我也不起作用,应用程序只是冻结了。
BeginInvoke
工作正常,但我不喜欢异步更新UI控件的效果


我最终将主进程作为一个单独的线程启动(
System.Threading.Tasks.Task
),它将启动并立即返回主线程的控制权。之后,在等待几个其他任务在循环中结束执行时,我还不得不插入以下行:
System.Windows.Forms.Application.DoEvents()
,以使系统能够处理队列中等待的所有消息。现在它适用于我的应用程序。可能有另一种方法可以剥下这只猫的皮,但它现在可以工作了。

此评论适用于我的特定应用程序,它是C#中的Windows应用程序:使用锁对我也不起作用,应用程序只是冻结了。
BeginInvoke
工作正常,但我不喜欢异步更新UI控件的效果


我最终将主进程作为一个单独的线程启动(
System.Threading.Tasks.Task
),它将启动并立即返回主线程的控制权。之后,在等待几个其他任务在循环中结束执行时,我还不得不插入以下行:
System.Windows.Forms.Application.DoEvents()
,以使系统能够处理队列中等待的所有消息。现在它适用于我的应用程序。可能有另一种方法可以剥这只猫的皮,但它现在可以工作了。

您不能使用
BeginInvoke
而不是
Invoke
?否,因为我需要阻止,直到UpdateRepresentation()返回。因为在Parallel.ForEach()之后,我对一些方法进行了一些其他调用。这可能是一个愚蠢的问题,但是View是否有一个Dispatcher以便您可以执行View.Dispatcher.Invoke()?是否需要在UI线程上调用
MyRepresentation
的构造函数?类似的问题(以及可能的解决方案)已在此处发布:您不能使用
BeginInvoke
而不是
Invoke