5

这会通知未处理的异常:

new Thread(_ => { throw new Exception(); }).Start();

这不会(至少在您等待/检索结果之前):

Task.Factory.StartNew(() =>
        {
            throw new Exception();
        });

为什么?抛出异常的线程发生了什么?它会死吗?

这是您运行任务但不需要其结果或需要等待它的问题,如下所示:

_operationQueue = new BlockingCollection<Operation>();

Task.Factory.StartNew(() => 
{
     foreach (var item in _operationQueue.GetConsumingEnumerable())
     {
         // do something that throws
     }
}, TaskCreationOptions.LongRunning);

在这种情况下,_operationQueue剩下的状态是什么?

我知道我可以将 Continuation 与 TaskContinuationOptions.OnlyOnFaulted 一起使用,你能恢复处理吗?

4

2 回答 2

9

那么,你假设应该发生什么?您是否认为每当在另一个线程中引发异常时,它应该立即传播到启动该任务的线程?我强烈反对。首先,调用线程中的代码将被迫中止它正在执行的操作,这很可能会导致严重的问题。只需查看周围的所有帖子Thread.Abort,即可查看当您允许在程序执行中的某个任意点而不是某些已知点引发异常时出现的所有非常重要的问题。

如果您建议当任务的代码引发异常时整个程序应该崩溃,那么我会说这基本上是不可取的。在极少数情况下,您可以(相当容易地)在任务上创建一个延续,如果任务出现故障,该延续会结束整个过程。不过,我还需要自己创建这样的延续。如果系统设计为在任务引发异常时关闭进程,那么获得相反的行为就不会那么容易了。

抛出异常的线程发生了什么?它会死吗?

如果捕获到异常,则在捕获后继续执行;如果它通过整个调用堆栈传播,则异常将被Task框架内的代码捕获,该代码包装异常并使其可用于延续。

在这种情况下,_operationQueue 处于什么状态?

这是一个非常好的队列,已经从中删除了 1..N 个项目。如果循环的主体总是抛出,那么就会从中取出一项。如果它只是偶尔抛出,那么会从中取出一些物品。剩余的项目仍在队列中,可以被任何其他有权访问它的线程删除。如果队列不再可访问,那么它将有资格进行垃圾收集。

我知道我可以将 Continuation 与 TaskContinuationOptions.OnlyOnFaulted 一起使用,你能恢复处理吗?

调用线程可以;当然。任务本身只能通过try/catch在其委托中继续执行。如果异常已经被抛出到任务出错的地步,那么任何事情都不会允许该任务继续执行。

于 2013-06-17T15:47:43.377 回答
3

任务中的异常被TaskScheduler. 如果您从不想观察任务的结果,但希望在任务中未处理的异常时收到通知,则有TaskScheduler.UnobservedTaskException事件。请注意,此事件不会立即触发,而是在完成时触发,Task如果从未检索到异常。在 .Net 4 中,未观察到的任务异常被重新抛出并成为结束进程的未处理异常,但在 .Net 4.5 中改变了这一点。

于 2013-06-17T15:55:09.010 回答