Using the Thread-compatible Exception Classes
The base class in the Thread-compatible Exception package is
RWTHRxmsg, which derives from the class
RWxmsg, from the Essential Tools Module. A thread-compatible exception can be copied and stored, so that it can be rethrown in the future. This capability, which makes passing across thread boundaries possible, comes from the
RWTHRxmsg member functions
clone() and
raise(). For more information about passing exceptions across thread boundaries, see
“Catching and Rethrowing Exceptions.”Creating Your Own Exception Classes
Any special-purpose exception classes you derive from
RWTHRxmsg will be thread-compatible. You must redefine the
clone() and
raise() members in your exception classes. For your convenience, Threads Module provides the following macros that expand into the
clone() and
raise() code.
RW_THR_DECLARE_EXCEPTION(yourClassName)
Declares the clone() and raise() member functions. This macro must be placed inside your class declaration.
RW_THR_IMPLEMENT_EXCEPTION(yourClassName)
Provides the definitions for the clone() and raise() member functions declared by the matching DECLARE macro (above). This macro must be placed in the implementation (.cpp) file for your class.
RW_THR_IMPLEMENT_TRACEABLE_EXCEPTION(yourClassName)
Used instead of the
RW_THR_IMPLEMENT_EXCEPTION macro where entry/exit tracing is desired for the
clone() and
raise() member functions. (See
Chapter 6, “The Execution Tracing Package.”)
RW_THR_DECLARE_INLINE_EXCEPTION(yourClassName)
Used instead of the RW_THR_DECLARE_EXCEPTION macro to provide inline definitions for the clone() and raise() member functions. This macro must be placed inside your class declaration. You use this macro alone for inline definitions; you do not need either of the IMPLEMENT macros listed above. If you want your functions to have entry/exit tracing, you cannot define them inline.
Creating Your Own Error Handler
If you want to handle all types of exceptions the same way, such as writing out their messages, you need only one catch block for the base class. For example, suppose that your application uses the combination of predefined and user-defined exception classes shown in
Figure 51 .
You could log all the exceptions of type
RWxmsg,
RWTHRxmsg, and
MYxmsg with the simple statement shown in
Example 69 .
Example 69 – Implementing a simple error handler
catch(RWxmsg& emsg) {
...
cout << "Oh-oh: " << emsg.why() << endl;
...
}
Because
RWTHRxmsg and
MYxmsg derive from
RWxmsg, this code catches all these exceptions.
If you want to do something different with each exception type, however, you need three separate catch blocks with the most derived type handled first, as shown in
Example 70 .
Example 70 – Handling multiple exception types differently
catch(MYxmsg& emsg) {
...
handle my special-purpose thread-compatible exceptions
...
}
catch(RWTHRxmsg& emsg) {
...
handle the generic thread-compatible exceptions
...
}
catch(RWxmsg& emsg) {
...
handle the non-thread-compatible C++ exceptions
...
}
For more information, see the discussion of error handlers in the Essential Tools Module User’s Guide.
Making Existing Exceptions Thread-Compatible
You can create a thread-compatible exception from any existing non-compatible exception class. Thread-compatible Exception provides the template class
RWTTHRCompatibleException<Exception>, which acts as a wrapper to your legacy exception class. An
RWTTHRCompatibleException is stored like any other exception type. But instead of rethrowing itself, its
raise() member function causes the legacy exception to be rethrown. See the
SourcePro API Reference Guide for more information.