The following is a convenience class for wrapping up the
initialization of an arbitrary object into a function local static. It
relys on pthread_once and the pthread thread local storage API. The
pthread thread local storage is wrapped into its own convenience class
ThreadLocal<>. If anyone thinks they need that as well I'd be happy to
share it.
template<class T>
class OnceHelper
{
T **_ptr;
public:
OnceHelper() : _ptr(0) {}
inline void Set(T **ptr) { _ptr = ptr; }
inline T **Get() { return _ptr; }
};
template<class T>
struct Once
{
T *_obj;
pthread_once_t _once;
// ThreadLocal will construct and destruct during single-threaded
// program startup and teardown
static ThreadLocal<OEOnceHelper<T> > _tls;
static void Init()
{
T **ptr = _tls->Get();
assert(ptr != 0);
*ptr = new T;
}
inline T *GetValue()
{
_tls->Set(&_obj);
if (pthread_once(&_once, Init) != 0)
perror("Problem with pthread_once");
return _obj;
}
~Once() { delete _obj; }
inline T& operator *() { return *GetValue(); }
inline T* operator ->() { return GetValue(); }
inline operator T* () { return operator ->(); }
};
#define ONCE_INIT { 0, PTHREAD_ONCE_INIT }
template<class T> ThreadLocal<OnceHelper<T> > Once<T>::_tls;
The usage looks something like this then:
void Foo()
{
static Once<Mutex> mutex = ONCE_INIT;
Lock lock(*mutex);
// do something thread-safely
}
My question deals with the GetValue workhorse method in the class.
Adding the following optimization where I check the _obj pointer
against being NULL can gain me as much as %10 in one of my
applications.
inline T *GetValue()
{
if (!_obj)
{
_tls->Set(&_obj);
if (pthread_once(&_once, Init) != 0)
perror("Problem with pthread_once");
}
return _obj;
}
The assumption is atomic pointer assignment on x86, x64, PPC, Sparc,
IA64 (the architectures I need to sup****t). If this isn't the case on
one of these, please let me know so I can ifdef the optimization out.
I'm almost tempted to say it's thread-safe "enough", but I know that
is asking for trouble. Any other optimizations some may see? I have an
equivalent class using Win32 intrinsics if anyone is interested as
well.
Thanks,
Brian


|