saving exceptions
My previous post explained the need to provide debugging context with C++ exception objects and provided an easy way to manually incorporate arbitrary pieces of context. An interesting suggestion is to incorporate a stack trace into the exception. This time, I’ll look at exceptions in a multi-threaded environment.
Termination style exceptions trace back to the notion of the “undefined” symbol in abstract functional programming. Any expression containing the undefined symbol evaluates to the undefined symbol. In C++, an “expression” is meticulously assembled on the stack. A throw statement is tantamount to dropping the undefined symbol into the expression embodied by the stack. Instead of simply reducing to a single symbol, the throw statement maps to a new expression (beginning with the catch statement) through the following steps:
- squirrels away an arbitrary piece of state, pushing it onto the exception stack,
- abandons the partially evaluated expression embodied by the current call stack,
- and then evaluates a sequence of catch handlers.
Many multi-threaded scenarios can be mapped onto the “futures pattern”. A primary thread initiates an asynchronous action and retains the option to retrieve a result at a later time, through a proxy object that represents a “future” value. In this scenario, the correct behavior is obviously that an exception be transfered from the asynchronous actor back to the primary thread when it attempts to retrieve the actual “future value”.
Thus, we want a mechanism to transfer and continue the cancellation action of an exception from an asynchronous actor to a primary thread. This transfer is passive, meaning there is a phase after the exception passes out of the asynchronous actor and before it enters the primary thread. (It is interesting to note that Haskell has an active “throwTo” transfer mechanism where a perpetrator thread can asynchronously inject an exception into a victim thread.)

Now - back to C++’s state squirreling. Our exception is held just outside the reach of the “catch” statement. We can only see the slice of it that corresponds to the catch declaration. This presents a bit of a problem when we try to implement something that transfers the exception between threads. The “re-throw” feature lets us transfer the hidden exception state between catch handlers within a thread. However, there is no mechanism that can either completely reveal the hidden state or transfer it to a second thread.
Of course, we need this to work in 2007. The simplest approximation of the exception_ptr system is to add a “cloneable_exception” base class with “clone” and “rethrow” virtual functions. However, this approach does not address exceptions thrown from 3rd party libraries. It builds in a kind of obscolescene, since the cloneable_exception base class will be unnecessary once we move to C++09.
I have prototyped a portable implementation, available here. My system requires that all exception types be registered (this is automatic for exceptions thrown using boost::throw_exception). The implementation still needs mutual exclusion protection for access to the exception type registry and reference counts. It effectively adds an “external clone” function to all registered exception types.