Online Book Reader

Home Category

Professional C__ - Marc Gregoire [391]

By Root 1489 0
futures. They also make it easier to handle errors that occur inside your threads. Futures are discussed later in this chapter.

Copying and Rethrowing Exceptions

The whole exception mechanism in C++ works perfectly, as long as it stays within one single thread. Every thread can throw its own exceptions, but they need to be caught within their own thread. Exceptions thrown in one thread cannot be caught in another thread. This introduces quite a few problems when you would like to use exception handling in combination with multithreaded programming.

Without C++11 it’s very difficult if not impossible to gracefully handle exceptions across threads. C++11 solves this issue with the following new exception-related functions:

exception_ptr current_exception() noexcept;

This function returns an exception_ptr object that refers to the exception currently being handled, or a copy of the currently handled exception, or a null exception_ptr object if no exception is being handled. This referenced exception object remains valid for as long as there is an object of type exception_ptr that is referencing it. exception_ptr is of type NullablePointer, which means it can easily be tested with a simple if statement as the example later in this section demonstrates.

[[noreturn]] void rethrow_exception(exception_ptr p);

This function rethrows the exception referenced by the exception_ptr parameter. Rethrowing the referenced exception does not have to be done in the same thread that generated the referenced exception in the first place, which makes this feature perfectly suited for handling exceptions across different threads. The [[noreturn]] attribute makes it clear that this function will never return normally and is introduced in Chapter 9.

template exception_ptr make_exception_ptr(E e) noexcept;

This function creates an exception_ptr object that refers to a copy of the given exception object. This is basically a shorthand notation for the following code:

try {

throw e;

} catch(...) {

return current_exception();

}

Let’s see how handling exceptions across different threads can be implemented by using these new features.

The following code defines a function that does some work and throws an exception. This function will ultimately be running in a separate background thread:

void doSomeWork() throw(runtime_error)

{

for (int i = 0; i < 5; ++i)

cout << i << endl;

cout << "Thread throwing a runtime_error exception..." << endl;

throw runtime_error("Exception from thread");

}

Code snippet from ExceptionsWithThreads\ExceptionsWithThreads.cpp

The following threadFunc() function wraps the call to the preceding function in a try/catch block, which will catch all exceptions that doSomeWork() might throw. A single argument is supplied to threadFunc(), which is of type exception_ptr&. Once an exception is caught, the function current_exception() is used to get a reference to the exception being handled, which is then assigned to the exception_ptr parameter. After that, the thread exits normally:

void threadFunc(exception_ptr& err)

{

try {

doSomeWork();

} catch (...) {

cout << "Thread caught exception, returning exception..." << endl;

err = current_exception();

}

}

Code snippet from ExceptionsWithThreads\ExceptionsWithThreads.cpp

The following doWorkInThread() function is called from within the main thread. Its responsibility is to create a new thread and start executing the preceding threadFunc() function in it. A reference to an object of type exception_ptr is given as argument to threadFunc(). Once the thread is created, the doWorkInThread() function waits for the thread to finish by using the join() method, after which the error object is examined. Since exception_ptr is of type NullablePointer, you can easily check it by using if (error). If it’s a non-null value, the exception is rethrown in the current thread, which is the main thread in this example. By rethrowing the exception in the main thread, the exception has been transferred from one thread to another thread.

void doWorkInThread() throw(runtime_error)

Return Main Page Previous Page Next Page

®Online Book Reader