0

我正在 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(主窗体)内的一个 Control。

当应用程序变得无响应时,我从 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>

任何帮助将不胜感激。

4

3 回答 3

7

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

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

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

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

一般来说,长时间阻塞UI线程并不是一个好主意,所以你应该在另一个线程上运行任何耗时的代码。

于 2012-05-15T14:28:53.953 回答
1

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

使用开始调用方法

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

}
于 2012-05-15T13:56:59.677 回答
-1

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

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

于 2015-07-27T16:42:26.347 回答