[351] in Pthreads mailing list archive
Fix to init pthreads earlier in C++
daemon@ATHENA.MIT.EDU (Rob Browning)
Fri Jul 5 14:40:50 1996
To: pthreads@MIT.EDU
From: Rob Browning <osiris@cs.utexas.edu>
Date: 05 Jul 1996 13:21:40 -0500
The way pthreads is set up right now, you can't use pthreads calls
reliably in static initialization code in C++ because pthreads might
not be initialized. The static initialization trick in
pthreads/init.cc is only guaranteed to fire before main, but not
necessarily before static constructors for other objects. However,
there is an "easy" fix for this. It's documented in Ellis and
Stroustroup p.20, and they claim it's pretty common, and that it has
been used in iostreams...
The reason the solution's so awkward (if you care) is that C++ says
nothing about the order that statics will be initialized, but it does
guarantee that all statics will be *zeroed* before any static
initializers fire. This fact can be used to make sure that if you
include pthread.h in any C++ file, pthreads will be initialzed before
any static initializers fire for any classes mentioned after the
#include <pthread.h>. In other words, just including pthread.h forces
pthreads to be initialized at the point of inclusion. There is also
the added advantage that this provides a hook for handling things that
should happen when the last file is finished using pthreads at exit
time.
I'm pretty certain that this hack will work for plain C code just as
well as the old method, but some testing would be in order.
First thing that has to be changed: the step in the makefile that
compiles init.cc must have a -Iinclude flag. Otherwise on systems
with older pthreads libraries already installed, you'll get trouble.
Next, change pthread/init.cc to read:
(Disclaimer: any of the code I wrote in this message is under the same
copyright as pthreads. What I'm trying to say is that Chris is
welcome to it.)
=================================================================
#include <pthread.h>
/* In case this is still needed for C only compiles */
char __pthread_init_hack = 42;
unsigned long _pthreadUsageCounter::count_;
pthread_mutex_t *_pthreadUsageCounter::mutex_;
=================================================================
Then add this bit to the end of include/pthread.h (just before the
final #endif):
=================================================================
#ifdef __cplusplus /* (RLB) -- down to endif */
extern char _pthread_init_hack;
class _pthreadUsageCounter {
private:
// Guaranteed to be zeroed *before* *any* static initializers
// fire, but that's all.
static unsigned long count_;
static pthread_mutex_t *mutex_;
public:
_pthreadUsageCounter() {
if(count_ == 0) {
// No other threads could have been launched at this point,
// b/c to do so would require a pthread function, and since
// this class will only be used as a static, and since C++
// guarantees that all statics are inited before any functions
// are called...
pthread_init ();
mutex_ = new pthread_mutex_t;
pthread_mutex_init(mutex_, NULL);
}
pthread_mutex_lock(mutex_);
count_++;
pthread_mutex_unlock(mutex_);
}
~_pthreadUsageCounter() {
pthread_mutex_lock(mutex_);
unsigned long count = --count_;
pthread_mutex_unlock(mutex_);
if(count == 0) {
// do any class global cleanup
pthread_mutex_destroy(mutex_);
delete mutex_;
}
}
};
static _pthreadUsageCounter _pthread_usage_counter___;
#endif /* __cplusplus */
=================================================================
That's it. Recompile, reinstall, and you should be set.
--
Rob