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

你。 提交于 2019-12-29 02:47:30

问题


If I have a C++11 program running two threads, and one of them throws an unhandled exception, what happens? Will the entire program die a fiery death? Will the thread where the exception is thrown die alone (and if so, can I obtain the exception in this case)? Something else entirely?


回答1:


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.




回答2:


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 called

thread.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 run
launched.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 get
auto handle = [](std::future<T> future)
{
    // get either the value returned by run
    // or the exception it threw
    future.get();
};

// std::future is move-only
std::async(handle, std::move(launched));
// we didn't name and use the return of std::async
// because we don't have to


来源:https://stackoverflow.com/questions/7272093/what-happens-when-an-exception-goes-unhandled-in-a-multithreaded-c11-program

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!