如何确保异常“调用线程无法访问该对象,因为它被另一个线程拥有”

本文关键字:线程 对象 因为 拥有 另一个 访问 确保 何确保 异常 调用 | 更新日期: 2023-09-27 18:07:15

在c# WPF应用程序中,如果在下列按钮中单击事件处理程序:

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()输出到textblock,然后它被不同的线程id填充。

尽管有注释行,如上面所示,textblock保持空白,并且没有抛出异常。

类似情况下使用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() ?
有什么方法可以保证这个异常吗?

如何确保异常“调用线程无法访问该对象,因为它被另一个线程拥有”

任务中抛出的异常总是由Task对象本身处理。稍后,当您(例如,访问Task)时,会重新抛出异常。结果属性。这样,异常的处理就留给了创建Task的线程。如果您运行第一个代码片段并查看Output窗格,您将看到那里记录了多个首次出现的InvalidOperationException。异常抛出——任务只是把它们藏起来,以便以后重新抛出。

Parallel.For实际上做了同样的事情—它隐藏了委托中发生的所有异常,然后,当循环完成时,它重新抛出单个AggregateException中发生的所有异常。您会注意到调试器在调用Parallel.For的线程中中断,而不是在传递给它的委托中中断。

要使任务中的异常像Parallel.For一样传播到调用线程,请在任务上调用Wait/WaitAll