catch exception that is thrown in different thread

105,768

Solution 1

In .NET 4 and above, you can use Task<T> class instead of creating new thread. Then you can get exceptions using .Exceptions property on your task object. There are 2 ways to do it:

  1. In a separate method: // You process exception in some task's thread

    class Program
    {
        static void Main(string[] args)
        {
            Task<int> task = new Task<int>(Test);
            task.ContinueWith(ExceptionHandler, TaskContinuationOptions.OnlyOnFaulted);
            task.Start();
            Console.ReadLine();
        }
    
        static int Test()
        {
            throw new Exception();
        }
    
        static void ExceptionHandler(Task<int> task)
        {
            var exception = task.Exception;
            Console.WriteLine(exception);
        }
    }
    
  2. In the same method: // You process exception in the caller's thread

    class Program
    {
        static void Main(string[] args)
        {
            Task<int> task = new Task<int>(Test);
            task.Start();
    
            try
            {
                task.Wait();
            }
            catch (AggregateException ex)
            {
                Console.WriteLine(ex);    
            }
    
            Console.ReadLine();
        }
    
        static int Test()
        {
            throw new Exception();
        }
    }
    

Note that the exception which you get is AggregateException. All real exceptions are availible through ex.InnerExceptions property.

In .NET 3.5 you can use the following code:

  1. // You process exception in the child's thread

    class Program
    {
        static void Main(string[] args)
        {
            Exception exception = null;
            Thread thread = new Thread(() => SafeExecute(() => Test(0, 0), Handler));
            thread.Start();            
    
            Console.ReadLine();
        }
    
        private static void Handler(Exception exception)
        {        
            Console.WriteLine(exception);
        }
    
        private static void SafeExecute(Action test, Action<Exception> handler)
        {
            try
            {
                test.Invoke();
            }
            catch (Exception ex)
            {
                Handler(ex);
            }
        }
    
        static void Test(int a, int b)
        {
            throw new Exception();
        }
    }
    
  2. Or // You process exception in the caller's thread

    class Program
    {
        static void Main(string[] args)
        {
            Exception exception = null;
            Thread thread = new Thread(() => SafeExecute(() => Test(0, 0), out exception));
    
            thread.Start();            
    
            thread.Join();
    
            Console.WriteLine(exception);    
    
            Console.ReadLine();
        }
    
        private static void SafeExecute(Action test, out Exception exception)
        {
            exception = null;
    
            try
            {
                test.Invoke();
            }
            catch (Exception ex)
            {
                exception = ex;
            }
        }
    
        static void Test(int a, int b)
        {
            throw new Exception();
        }
    }
    

Solution 2

You can not catch the exception in Method1. You can, however, catch the exception in Method2 and record it to a variable that the original thread of execution can then read and work with.

Solution 3

I had a particular problem in that I wanted to use items, containing controls, from an integration test suite, so have to create an STA thread. The code I ended up with is as follows, put here in case others have the same issue.

    public Boolean? Dance(String name) {

        // Already on an STA thread, so just go for it
        if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA) return DanceSTA(name);

        // Local variable to hold the caught exception until the caller can rethrow
        Exception lException = null;

        Boolean? lResult = null;

        // A gate to hold the calling thread until the called thread is done
        var lGate = new ManualResetEvent(false);

        var lThreadStart = new ThreadStart(() => {
            try {
                lResult = DanceSTA(name);
            } catch (Exception ex) {
                lException = ex;
            }
            lGate.Set();
        });

        var lThread = new Thread(lThreadStart);
        lThread.SetApartmentState(ApartmentState.STA);
        lThread.Start();

        lGate.WaitOne();

        if (lException != null) throw lException;

        return lResult;
    }

    public Boolean? DanceSTA(String name) { ... }

This is a direct paste of the code as-is. For other uses I would recommend supplying an action or function as a parameter and invoking that on the thread instead of hard-coding the called method.

Share:
105,768
Silverlight Student
Author by

Silverlight Student

Updated on November 06, 2021

Comments

  • Silverlight Student
    Silverlight Student over 2 years

    One of my method (Method1) spawns a new thread. That thread execute a method (Method2) and during exectution an exception is thrown. I need to get that exception information on the calling method (Method1)

    Is there someway I can catch this exception in Method1 that is thrown in Method2?

  • Silverlight Student
    Silverlight Student about 13 years
    Thanks for your response. So If Method1 is part of Class1 and I have an variable of type Exception in that class. Whenever Method2 throws an exception, it sets that exception variable in Class1 also. Does it sound like a fair design? Are there any best practice ways of handling this scenario?
  • Silverlight Student
    Silverlight Student about 13 years
    Sorry but I forgot to mention that I am using .NET 3.5. As per my understanding Task is 4.0 thing?
  • Santanu Maulik
    Santanu Maulik about 13 years
    Correct, you just store the exception and access it later. It's not uncommon for methods run in the future (especially callbacks for when Method2 is complete) to then rethrow that exception as if they themselves had caused it, but this really depends on what you want.
  • oxilumin
    oxilumin about 13 years
    @SilverlightStudent Ok, I just updated my answer to satisfy your requirements.
  • Silverlight Student
    Silverlight Student about 13 years
    @oxilumin: Thanks and much appreciated. One more followup question. If your Test() method takes a few arguments too, then how will you modify SafeExecute method for those arguments?
  • oxilumin
    oxilumin about 13 years
    @SilverlightStudent In this case I'll pass a lambda instead of Test. Like () => Test(myParameter1, myParameter2)
  • Silverlight Student
    Silverlight Student about 13 years
    @oxilumin: Thanks again, however when I try to do it I am getting compilation errors. Is it possible for you to update example above for that scenario of have to pass in multiple parameters?
  • oxilumin
    oxilumin about 13 years
    @SilverlightStudent: Updated.
  • Peter Kelly
    Peter Kelly over 12 years
    The exception still goes unhandled before then going on to the catch block in the main thread.
  • Essej
    Essej over 3 years
    I get compilation errors, "Cannot convert from int to System.Func<int>"