Catching and Rethrowing Exceptions
Exceptions produced while executing a runnable’s task are captured by the runnable for later recovery. Any of these exceptions can be rethrown by any thread that has access to the runnable object. This operation is implemented by the following function:
• void RWRunnable::raise(void) const
A runnable catches any exception that propagates out of its run() member function. This includes any exceptions produced by functions invoked as functors within the runnable. When a runnable catches an exception, it:
1. Makes an internal copy of the exception.
2. Sets the execution state to RW_THR_EXCEPTION[5].
3. Sets the completion state to RW_THR_FAILED{3}.
4. Sets the execution state to RW_THR_INITIAL[6].
5. Ceases execution by returning from start() or exiting the thread.
Any exception caught by the runnable can then be recovered by rethrowing the exception using the RWRunnable::raise() function. If no exception has occurred, this function returns without doing anything.
Testing After Successful Joins
You should test for an exception each time you successfully join with a runnable, as shown in
Example 7 .
Example 7 – Testing for an exception after joining with a runnable
RWThreadFunction myThread = ...;
try {
myThread.start(); // Start the runnable
myThread.join(); // Join the runnable
myThread.raise(); // Rethrow any exception that was caught!
}
catch(RWTHRxmsg& msg) {
cout << "Exception! " << msg.why() << endl;
}
Types of Rethrown Exceptions
The type of exception that is rethrown by a runnable might not match the original exception class that was thrown or caught.
• If the exception is based on the
RWTHRxmsg class, then the exception rethrown by
raise() is of the same class as the one captured.
• Exceptions based on the
RWxmsg (or
xmsg) class are rethrown as an
RWxmsg with the same message value as the captured exception.
• Any other type of exception is rethrown as an
RWTHRxmsg with a generic message stating that the captured exception was of an unrecognized type.
When designing code that you expect to execute inside a Threading package runnable, you might want to use the
RWTHRxmsg class as a base class for your exceptions. An exception derived from this class can be caught as an
RWTHRxmsg, copied for storage using a virtual
clone() function, and later “reconstituted” using a virtual
raise() function defined by the class. This
store-and-forward capability allows a runnable to capture and rethrow an exception.
The Threading package includes a template called
RWTTHRCompatibleException, which can convert an existing exception class into an
RWTHRxmsg-compatible exception.