What happens when an exception goes unhandled in a multithreaded C++11 program? What happens when an exception goes unhandled in a multithreaded C++11 program? multithreading multithreading

What happens when an exception goes unhandled in a multithreaded C++11 program?


Nothing has really changed. The wording in n3290 is:

If no matching handler is found, the function std::terminate() is called

The behavior of terminate can be customized with set_terminate, but:

Required behavior: A terminate_handler shall terminate execution of the program without returning to the caller.

So the program exits in such a case, other threads cannot continue running.


Since there seems to be legitimate interest in exception propagation and this is slightly at least somewhat relevant to the question, here's my suggestion: std::thread is to be considered an unsafe primitive to build e.g. higher level abstractions. They're doubly risky exception-wise: if an exception goes off inside the thread we just launched, everything blows up, as we've shown. But if an exception goes off in the thread that launched the std::thread we may potentially be in trouble because std::thread's destructor requires that *this be either joined or detached (or equivalently, be not-a-thread). A violation of those requirements results in... a call to std::terminate!

A code map of the dangers of std::thread:

auto run = []{    // if an exception escapes here std::terminate is called};std::thread thread(run);// notice that we do not detach the thread// if an exception escapes here std::terminate is calledthread.join();// end of scope

Of course, some may argue that if we simply detached every thread that we launch we're safe on that second point. The problem with that is that in some situations join is the most sensible thing to do. The 'naive' parallelization of quicksort for instance requires to wait until the subtasks have ended. In those situations join serves as a synchronization primitive (a rendez-vous).

Lucky for us, those higher level abstractions I mentioned do exist and come with the Standard Library. They are std::async, std::future as well as std::packaged_task, std::promise and std::exception_ptr. The equivalent, exception-safe version of the above:

auto run = []() -> T // T may be void as above{    // may throw    return /* some T */;};auto launched = std::async(run);// launched has type std::future<T>// may throw here; nothing bad happens// expression has type T and may throw// will throw whatever was originally thrown in runlaunched.get();

And in fact instead of calling get in the thread that called async you can instead pass the buck to another thread:

// only one call to get allowed per std::future<T> so// this replaces the previous call to getauto handle = [](std::future<T> future){    // get either the value returned by run    // or the exception it threw    future.get();};// std::future is move-onlystd::async(handle, std::move(launched));// we didn't name and use the return of std::async// because we don't have to