C# 任务中的重试异常不存在';t使任务进入故障状态

C# 任务中的重试异常不存在';t使任务进入故障状态,c#,multithreading,task,thread-abort,C#,Multithreading,Task,Thread Abort,考虑以下场景 var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(2)); var startNew = Task.Factory.StartNew(() => { var currentThread = Thread.CurrentThread; try {

考虑以下场景

 var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(2));
        var startNew = Task.Factory.StartNew(() =>
        {
            var currentThread = Thread.CurrentThread;
            try
            {
                using (cancellationTokenSource.Token.Register(currentThread.Abort))
                    new AutoResetEvent(false).WaitOne(Timeout.InfiniteTimeSpan);
            }
            catch (ThreadAbortException abortException)
            {
                throw new TimeoutException("Operation timeouted", abortException);
            }
        }, cancellationTokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Current);
        startNew.ContinueWith(val => Console.WriteLine("Cancellation handled"), TaskContinuationOptions.OnlyOnCanceled);
        startNew.ContinueWith(val => Console.WriteLine("Fault handled"), TaskContinuationOptions.OnlyOnFaulted);
        startNew.ContinueWith(val => Console.WriteLine("Ran to completion handled"), TaskContinuationOptions.OnlyOnRanToCompletion);
抛开所有关于中止线程是邪恶的讨论不谈,为什么这段代码不让任务进入错误状态?但是,删除catch块或调用

Thread.ResetAbort()

这似乎是个诀窍

它是关于线程中止如何工作的:

try {
    try {
        try {
            Thread.CurrentThread.Abort();
        } catch(Exception e) {
            Console.WriteLine(e.GetType());
            throw new Exception();
        }
    } catch(Exception e) {
        Console.WriteLine(e.GetType());
    }
} catch(Exception e) {
    Console.WriteLine(e.GetType());
}
此代码打印:

System.Threading.ThreadAbortException
系统异常
System.Threading.ThreadAbortException
因此,在处理自定义异常时,
ThreadAbortException
将重新抛出

ThreadAbortException
是一种特殊异常,应用程序代码可以捕获它,但除非调用了
ResetAbort
,否则会在
catch
块的末尾重新抛出

现在让我们来看一些:

//
///执行任务。此方法将只调用一次,并处理与关联的簿记
///除了执行必要的异常封送之外,还可以执行自复制任务。
/// 
私有void Execute()
{
if(IsSelfReplicatingRoot)
{
ExecuteSelfReplicating(此);
}
其他的
{
尝试
{
InnerInvoke();
}
捕获(线程中止异常tae)
{
//不要为子副本任务记录TAE或调用FinishThreadAbortedTask--
//已经在下游完成了。
如果(!IsChildReplica)
{
//在任务的异常列表中记录此异常
手部异常(tae);
//这是一个ThreadAbortException,它将从此catch子句中重新引用,导致我们
//跳过常规的完成代码路径。为了不让任务未完成,我们现在调用
//在此完成线程中止任务。
FinishThreadAbortedTask(true,true);
}
}
捕获(异常exn)
{
//在任务的异常列表中记录此异常
手柄异常(exn);
}
}
}
正如您所看到的,对于
ThreadAbortException
case,有一个特殊的代码路径将任务转换到故障状态。当您通过
TimeoutException
隐藏
ThreadAbortException
时,不会采用特殊的代码路径。因此,当常规代码路径通过在任务的异常列表中记录异常来处理异常时,
ThreadAbortException
将被重新抛出,这将阻止任务正确转换到故障状态

/// <summary>
/// Executes the task. This method will only be called once, and handles bookeeping associated with
/// self-replicating tasks, in addition to performing necessary exception marshaling.
/// </summary>
private void Execute()
{
    if (IsSelfReplicatingRoot)
    {
        ExecuteSelfReplicating(this);
    }
    else
    {
        try
        {
            InnerInvoke();
        }
        catch (ThreadAbortException tae)
        {
            // Don't record the TAE or call FinishThreadAbortedTask for a child replica task --
            // it's already been done downstream.
            if (!IsChildReplica)
            {
                // Record this exception in the task's exception list
                HandleException(tae);

                // This is a ThreadAbortException and it will be rethrown from this catch clause, causing us to 
                // skip the regular Finish codepath. In order not to leave the task unfinished, we now call 
                // FinishThreadAbortedTask here.
                FinishThreadAbortedTask(true, true);
            }
        }
        catch (Exception exn)
        {
            // Record this exception in the task's exception list
            HandleException(exn);
        }
    }
}