2

C# WPF アプリケーションでは、次のボタンでイベント habdler をクリックします。

private void start_Click(object sender, RoutedEventArgs e)
{
  for (int i = 2; i < 20; i++)
  {
    var t = Task.Factory.StartNew
    (() =>
         {
            var result=Thread.CurrentThread.ManagedThreadId.ToString();
       //this.Dispatcher.BeginInvoke(new Action(() =>
            textBlock1.Text += "root " + i.ToString() + " " +
            result + Environment.NewLine
       ;//to comment this line if to uncomment th others
       //), null);
          }
     );
  }
}

コメント化された行のコメントを外します。つまり、テキストブロックに出力するDispatcher.BeginInvoke()と、さまざまなスレッド ID で埋められます。

上記のようにコメント行がありますが、テキストブロックは空白のままで、例外はスローされません。

同様の状況でParallel.For

private void start_Click(object sender, RoutedEventArgs e)
{
  Parallel.For(2, 6, (i) 
     => {
           var result = Thread.CurrentThread.ManagedThreadId.ToString();
           textBlock1.Text += "root " + i.ToString() + " " +
                               result + Environment.NewLine;

         }   );
}

アプリケーションは例外で壊れます:

「別のスレッドが所有しているため、呼び出し元のスレッドはこのオブジェクトにアクセスできません」

を使用しているときに、最初のケースでスローされないのはなぜTask.Factory.StartNew()ですか?
この例外を確実にする方法はありますか?

4

1 に答える 1

3

タスクでスローされた例外は、常に Task オブジェクト自体によって処理されます。たとえば、Task.Result プロパティにアクセスすると、後で例外が再スローされます。このようにして、例外の処理はタスクを作成するスレッドに任されます。最初のコード スニペットを実行して [出力] ペインを見ると、複数の最初のチャンスの InvalidOperationException がログに記録されていることがわかります。例外スローされます。タスクは、後で再スローするためにそれらを隠しておきます。

Parallel.For実際には同じことを行います。デリゲート内で発生したすべての例外を隠し、ループが終了すると、単一の で発生したすべての例外を再スローしますAggregateException。デバッガーは、Parallel.For渡されたデリゲート内ではなく、 を呼び出しているスレッド内で中断することがわかります。

タスクの例外を呼び出し元のスレッドに伝播させるには、タスクを呼び出しParallel.ForますWait/WaitAll

于 2013-04-02T13:38:33.747 に答える