如何确保异常“调用线程无法访问该对象,因为它被另一个线程拥有”
本文关键字:线程 对象 因为 拥有 另一个 访问 确保 何确保 异常 调用 | 更新日期: 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
。