C# 使用长时间运行的后台使用者任务时,Task.Factory.StartNew中是否存在静默异常?

C# 使用长时间运行的后台使用者任务时,Task.Factory.StartNew中是否存在静默异常?,c#,.net,exception,task-parallel-library,task,C#,.net,Exception,Task Parallel Library,Task,这将通知未处理的异常: new Thread(_ => { throw new Exception(); }).Start(); 这不会(至少在您等待/检索结果之前): 为什么??引发异常的线程发生了什么?它死了吗 这是一个运行任务但不需要其结果,或需要等待其结果的问题,如下所示: _operationQueue = new BlockingCollection<Operation>(); Task.Factory.StartNew(() => { for

这将通知未处理的异常:

new Thread(_ => { throw new Exception(); }).Start();
这不会(至少在您等待/检索结果之前):

为什么??引发异常的线程发生了什么?它死了吗

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

_operationQueue = new BlockingCollection<Operation>();

Task.Factory.StartNew(() => 
{
     foreach (var item in _operationQueue.GetConsumingEnumerable())
     {
         // do something that throws
     }
}, TaskCreationOptions.LongRunning);
\u operationQueue=new BlockingCollection();
Task.Factory.StartNew(()=>
{
foreach(在_operationQueue.GetConsumingEnumerable()中的变量项)
{
//做一些会扔东西的事
}
},TaskCreationOptions.LongRunning);
在这种情况下,
\u操作队列
处于什么状态


我知道我可以将延续与TaskContinuationOptions一起使用。只有出现故障时,才能继续处理吗

那么,你认为应该发生什么呢?您是否认为每当在另一个线程中抛出异常时,它应该立即传播到启动该任务的线程?我强烈反对。首先,调用线程中的代码将被迫中止其中间的操作,这很可能导致重大问题。只要查看一下关于
Thread.Abort
的所有文章,就可以看到当您允许在程序执行过程中的某个任意点而不是某些已知点抛出异常时出现的所有非常重要的问题

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

引发异常的线程发生了什么?它死了吗

如果捕获到异常,则在捕获后继续执行;如果它在整个调用堆栈中传播,那么异常将被
任务
框架中的代码捕获,该框架包装异常并使其可用于continuations

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

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

我知道我可以将延续与TaskContinuationOptions一起使用。只有出现故障时,才能继续处理吗


调用线程可以;当然任务本身只有在其委托中有一个
try/catch
才能继续。如果异常已引发到任务出现故障的程度,则任何操作都不会允许该任务继续执行。

任务调度程序将捕获任务中的异常。如果您从不希望观察任务的结果,但希望收到任务中未处理异常的通知,则会出现
TaskScheduler.unobservedtaskeexception
事件。请注意,如果从未检索到异常,则此事件不会立即触发,而是在任务完成后触发。在.NET4中,未观察到的任务异常被重新处理,并成为结束进程的未处理异常,但在.NET4.5中发生了更改

_operationQueue = new BlockingCollection<Operation>();

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