Exception exception in the task does not cause the task to go into a failure state

Consider the following scenario

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

Having discarded all discussions that thread interruption is evil, why does this code not cause the task to transition to the Faulted state? However removing the catch block or calling

Thread.ResetAbort()

seems to be doing the trick

+1
source share
1 answer

This is about how thread interruption 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());
}

This code prints:

System.Threading.ThreadAbortException
System.Exception
System.Threading.ThreadAbortException

So, when your custom exception is handled ThreadAbortException, that will be re-inserted.

ThreadAbortException- A special exception that can be caught by the application code, but re-selected at the end of the block catch, if not called ResetAbort. MSDN

source:

/// <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 already been done downstream.
            if (!IsChildReplica)
            {
                // Record this exception in the task 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 exception list
            HandleException(exn);
        }
    }
}

, ThreadAbortException . ThreadAbortException TimeoutException, . , , ThreadAbortException , .

+2

Source: https://habr.com/ru/post/1599199/


All Articles