Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exception handling : Thread v/s Task

Tags:

c#

Thread version results in unhandled exception, which crashes the app but the task version doesn't. Both are running exactly the same method Can someone explain the reason for this difference in exception behavior ?

Thread version:

            try
            {
                new Thread(new ThreadStart(DoWork)).Start();  // do work throws exception
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }

        static void DoWork()
        {
            Console.WriteLine("in thread");
            throw new Exception();
        }

Task version:

      var errorTask = Task.Factory.StartNew<Func<string>>(() =>
                {
                    Console.WriteLine("in task");
                    throw new Exception();
                });

            try
            {
                string result = errorTask.Result();
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
like image 592
C.Dhruv Avatar asked Nov 14 '17 05:11

C.Dhruv


2 Answers

Thread.Start starts new thread, but you're handling exception in another thread:

try
{
    // DoWork throws exception in new thread;
    // threads don't catch exceptions out-of-the-box
    new Thread(new ThreadStart(DoWork)).Start();
}
catch (Exception e)
{
    // you're handling exception in "old" thread
    Console.WriteLine(e);
}

Task.Factory.StartNew starts new task. Task catches exception inside it to set its Status property:

var errorTask = Task.Factory.StartNew<Func<string>>(() =>
{
    Console.WriteLine("in task");

    // this exception will be caught in Task's base code,
    // since tasks catch exceptions thrown by task methods;
    // note, that this will be wrapped into AggregateException
    throw new Exception();
});

when you're trying to get Task.Result, and task is in faulted state, it just re-throws exception:

// this will re-throw exception in calling thread
string result = errorTask.Result;

That's why your second catch catches it.

like image 139
Dennis Avatar answered Nov 20 '22 18:11

Dennis


To shed some light on the topic one could consult the documentation for Task.Result<TResult>() (or the one for Task.Wait() for what it's worth).

Under thrown exceptions (particularly AggregateException) is says

An exception was thrown during the execution of the task. The AggregateException.InnerExceptions collection contains information about the exception or exceptions.

A Task is kind of a managed thread (in very simple terms) which gives us some merits, e.g. this exception handling when accessing Result or Wait (or using await). On the other hand a Thread will execute separately from the method you are calling it from. You start the thread an (virtually) immediately leave the try / catch block. There is no way to know for the thread that there is an associated try / catch. Basically the thread does not know anything about the calling function. The other way round, if the calling function blocked its own thread to wait for the thread it created, just to make use of the try / catch this would basically render creating new threads useless.

like image 1
Paul Kertscher Avatar answered Nov 20 '22 18:11

Paul Kertscher