ThreadSafeErrorLog
Using the naive ErrorLog mechanism, two threads issuing error messages at overlapping times will each send instructions to the same ELadministrator. This leads to the possibility of garbled messages. Instead, what is wanted is some way for each thread to independently compose a message, and each message to emerge as one uninterrupted chunk on the destinations.
The strategy employed is that the ThreadSafeErrorLog has its own area for building up a message, rather than using the common one in ELadministrator. When the message is completed, the ThreadSafeErrorLog will obtain a lock on the right to be sending a message to the administrator, send the message, and release the lock.
An example of how this can be used is supplied in
MultThread.h and
MultThread.cc.
Here, care is taken to set things up so that each thread has its own
ThreadSafeErrorLog, known as errlog.
Error messages are then issued in
exactly the same way as they would have been through the normal
errlog, and the behavior is also the same except that there will
be no garbling of the output.
Now the Exceptions package has no business dictating the actual locking
mechanism to the user. Instead, ThreadSafeErrorLog is templated
off an arbitrary user-defined class which we name Mutex.
The Mutex class must have two properties:
pthread_mutex_t* mutex; // a posix mutex, represented as a global
// scope pointer, initialized and set up
// at some early point in the job.
struct Mutex {
Mutex() { pthread_mutex_lock(mutex); }
~Mutex() { pthread_mutex_unlock(mutex); }
}
The latter method, having errlog as a public or protected ThreadSafeErrorLog data member in a Module class, works fine. Each thread, upon startup, instantiates whatever Modules it requires, and now each Module in each thread has its own ThreadSafeErrorLog which can accumulate its own message independant of activities of other threads.
For example, code in the MultThread example does something like:
And each thread has its own Module because the thread program starts with:
class Module {
public:
Module( const std::string & name );
virtual void operator()( Event & e ) = 0; // do this module's processing!
virtual ~Module();
protected:
ThreadSafeErrorLog
and causes the physics methods to be invoked via
DoPhysics doPhysics( name );
for ( n = 1; n < 20; ++n ) {
Event event( n );
doPhysics( event );
}