Catch Exception That Is Thrown in Different Thread

catch exception that is thrown in different thread

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

Catching exceptions caused in different threads

Generally speaking, it's easiest to catch the exceptions within the thread itself.

But if you want to catch the exception separately from the thread function itself (and if you can use Task instead of the old Thread approach), you can write code like this:

var task = Task.Factory.StartNew(() =>
{
throw new Exception("Test");
});

task.ContinueWith(t => handleException(t.Exception), TaskContinuationOptions.OnlyOnFaulted);

This uses ContinueWith() to call another method after the first thread has finished and an exception occurred, so you can log the exception or whatever:

static void handleException(AggregateException exception)
{
foreach (var ex in exception.Flatten().InnerExceptions)
Console.WriteLine(ex.Message);
}

This doesn't really let you fix anything up - the only sensible way to do that is to handle the exceptions properly in the thread function itself.

can't catch exception in main thread when other thread active and has try-catch

It's not so much that the exception isn't caught as it is that destroying a joinable thread terminates the process.
So your program terminates before the exception handler can be executed.

If you declare the thread outside the try-catch block, the exception will be caught.

Remember that you also need to join the thread if the exception was thrown.

How to catch an Exception from a thread

Use a Thread.UncaughtExceptionHandler.

Thread.UncaughtExceptionHandler h = new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread th, Throwable ex) {
System.out.println("Uncaught exception: " + ex);
}
};
Thread t = new Thread() {
@Override
public void run() {
System.out.println("Sleeping ...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("Interrupted.");
}
System.out.println("Throwing exception ...");
throw new RuntimeException();
}
};
t.setUncaughtExceptionHandler(h);
t.start();

Catch exception in current thread when it's thrown in different thread

The best way to achieve this is using the Task Parallel Library. If you start your task with TaskCreationOptions.LongRunning, a new thread will be created for the execution of the body of the task. You can then either access Task<T>.Result or call Wait from the main thread, and the exception (if any) will be propagated back to the thread. Use a CancellationTokenSource to support cancellation of other operations that are executing concurrently with the Go operation.

In the following example, calls to Thread.Sleep are placeholders for application-specific time consuming operations.

private static CancellationTokenSource _cancellationTokenSource =
new CancellationTokenSource();

static void Main(string[] args)
{
Task longRunning = Task.Factory.StartNew(Go, TaskCreationOptions.LongRunning);
while (true)
{
// Pass _cancellationTokenSource.Token to worker items to support
// cancelling the operation(s) immediately if the long running
// operation throws an exception
Thread.Sleep(1000);

// this will throw an exception if the task faulted, or simply continue
// if the task is still running
longRunning.Wait(0);
}
}

private static void Go()
{
try
{
Thread.Sleep(4000);
throw new Exception("Oh noes!!");
}
catch
{
_cancellationTokenSource.Cancel();
throw;
}
}

Will main() catch exceptions thrown from threads?


Will main() catch exceptions thrown from threads?

No

When a thread throws an exception, it is not caught by main. Is this the standard behavior?

Yes, this is standard behaviour.

To catch an exception originating in thread X, you have to have the try-catch clause in thread X (for example, around everything in the thread function, similarly to what you already do in main).

For a related question, see How can I propagate exceptions between threads?

catching exceptions from another thread

So you're using Invoke to marshall back to the UI thread, by the looks of it - which is exactly what you need to do. I'd personally use an Action<Exception> for simplicity's sake, and possibly BeginInvoke instead of Invoke, but basically you're doing the right thing.

Catching exception from worker thread in the main thread

Firstly, you do not need to use bind with thread. Doing so just adds unnecessary copying and makes the code harder to read. I wish everyone would stop doing that.

WorkerThread::WorkerThread(){

m_thread = boost::thread(&WorkerThread::drawThread, this);

}

You can store an exception in an exception_ptr and pass that to the other thread, e.g. in std::queue<std::exception_ptr>:

void WorkerThread::drawThread()
{
while(true)
{
boost::unique_lock<boost::mutex> lock(m_mutex);
try{

///some work is done here...

}catch(std::exception &e){
m_queue.push(std::current_exception());
}
}
}

std::exception_ptr WorkerThread::last_exception()
{
boost::lock_guard<boost::mutex> lock(m_mutex);
std::exception_ptr e;
if (!m_queue.empty())
{
e = m_queue.front();
m_queue.pop();
}
return e;
}

Then in the other thread rethrow it and handle it:

if (auto ep = workerThread.last_exception())
{
// do something with exception
try
{
std::rethrow_exception(ep);
}
catch (const std::exception& e)
{
std::cerr << "Error in worker thread: " << e.what() << '\n';
}
}

If you can't use std::exception_ptr Boost has its own implementation of it, but I'm not sure what the Boost equivalent of current_exception is. You might need to wrap the exception in another object so the Boost exception propagation mechanism can store it.

You might want to use a separate mutex for the exception queue from the main work loop (and move the m_mutex lock inside the try block) depending how long m_mutex is usually locked by the worker thread.


A different approach uses C++11 futures, which handle passing exceptions between threads more conveniently. You need some way for the main thread to get a future for each unit of work the worker thread runs, which can be done with std::packaged_task:

class WorkerThread
{
public:
WorkerThread(); // start m_thread, as before

template<typename F, typename... Args>
std::future<void> post(F f, Args&&... args)
{
Task task(std::bind<void>(f, std::forward<Args>(args)...));
auto fut = task.get_future();
std::lock_guard<std::mutex> lock(m_mutex);
m_tasks.push(std::move(task));
return fut;
}

private:
void drawThread();
std::mutex m_mutex;
using Task = std::packaged_task<void()>;
std::queue<Task> m_tasks;
std::thread m_thread;
};

void WorkerThread::drawThread()
{
Task task;
while(true)
{
{
std::lock_guard<std::mutex> lock(m_mutex);
task = std::move(m_tasks.front());
m_tasks.pop();
}
task(); // run the task
}
}

When the task is run any exceptions will be caught, stored in an exception_ptr and held until the result is read through the associated future.

// other thread:

auto fut = workerThread.post(&someDrawingFunc, arg1, arg2);
...
// check future for errors
try {
fut.get();
} catch (const std::exception& e) {
// handle it
}

The producer thread could store the future objects in a queue when posting work to the consumer, and some other piece of code could check each future in the queue to see if it's ready and call get() to handle any exception.



Related Topics



Leave a reply



Submit