0

VS2010Ultimateで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(メインフォーム)内のコントロールです。

アプリが応答しなくなったら、VSIDEから一時停止します。取得した情報は次のとおりです。

[並列タスク]ウィンドウで、次のように表示されます。

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()1つ以上のスレッドを使用して反復を実行し、すべての反復が完了するまで現在のスレッドをブロックします。

これはDoRepresentation()、UIスレッドから呼び出すと、デッドロックが発生することを意味します。UIスレッドは他のスレッドの反復が終了するのを待っていますが、他のスレッドは終了するのを待ってInvoke()います。これは、UIスレッドがブロックされている場合は発生しません。 。

また、あなたの場合、使用Parallel.ForEach()しても意味がありません(これが実際のコードであると仮定します)new MyRepresentation()。UIスレッドで実行します。

コードが正確に何をしているのかわかりませんが(反復ごとに上書きされるようです)、バックグラウンドスレッドからrepresentation実行する必要があると思います。ForEach()これはDoRepresentation()、作業が完了する前に戻るため、Invoke()正しく機能することを意味します。

一般に、UIスレッドを長時間ブロックすることはお勧めできません。そのため、時間のかかるコードを別のスレッドで実行する必要があります。

于 2012-05-15T14:28:53.953 に答える
1

Invokeメソッドの代わりにBeginInvokeを使用できます。それでも必要な場合は、オブジェクトをロックして、それが実現するまで他のスレッドからアクセスできないようにすることができます。

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

}
于 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 に答える