在Task中重新抛出异常不会使Task进入故障状态 [英] Rethrowing exception in Task doesn't make the Task to go to faulted state

查看:273
本文介绍了在Task中重新抛出异常不会使Task进入故障状态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下情况

 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);

撇开所有中止线程是邪恶的讨论,为什么这段代码没有使任务进入Faulted状态?但是删除catch块或调用

Putting aside all the discussion that aborting threads is evil, why does this code doesn't make the task to go to Faulted state? However removing catch block or calling

Thread.ResetAbort()

似乎可以解决问题

推荐答案

关于线程中止的工作方式:

It is about how thread abort works:

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.Exception
System.Threading.ThreadAbortException

因此,当您的自定义异常将得到处理时,ThreadAbortException谁将被重新抛出.

So, when your custom exception would be handled, ThreadAbortException whould be re-thrown.

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

ThreadAbortException is a special exception that can be caught by application code, but is re-thrown at the end of the catch block unless ResetAbort is called. MSDN

现在让我们看看一些:

/// <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);
        }
    }
}

如您所见,对于ThreadAbortException案例,有一个特殊的代码路径将任务转换为故障状态.当您用TimeoutException隐藏ThreadAbortException时,不会采用该特殊代码路径.因此,当常规代码路径通过将异常记录在任务的异常列表中来处理异常时,将重新抛出ThreadAbortException,这将阻止正确的任务转换为故障状态.

As you can see, there is special codepath for ThreadAbortException case to transit task to the faulted state. As you hide ThreadAbortException by TimeoutException, that special codepath are not taken. So when regular codepath handle exception by recording it in the task's exception list, ThreadAbortException would be re-thrown, which prevent correct task transition to the faulted state.

这篇关于在Task中重新抛出异常不会使Task进入故障状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆