As Scott Meyers and Andrei Alexandrescu outlined in this article the simple try to implement the double-check locking implementation is unsafe in C++ specifically and in general on multi-processor systems without using memory barriers.
I was thinking a little bit about that and came to a solution that avoids using memory barriers and should also work 100% safe in C++. The trick is to store a copy of the pointer to the instance thread-local so each thread has to acquire the lock for the first times it access the singleton.
Here is a little sample code (syntax not checked; I used pthread but all other threading libs could be used):
class Foo
{
private:
Helper *helper;
pthread_key_t localHelper;
pthread_mutex_t mutex;
public:
Foo()
: helper(NULL)
{
pthread_key_create(&localHelper, NULL);
pthread_mutex_init(&mutex);
}
~Foo()
{
pthread_key_delete(&localHelper);
pthread_mutex_destroy(&mutex);
}
Helper *getHelper()
{
Helper *res = pthread_getspecific(localHelper);
if (res == NULL)
{
pthread_mutex_lock(&mutex);
if (helper == NULL)
{
helper = new Helper();
}
res = helper;
pthread_mutex_unlock(&mutex);
pthread_setspecific(localHelper, res);
}
return res;
}
};
What are your comments/opinions?
Do you find any flaws in the idea or the implementation?
EDIT:
Helper is the type of the singleton object (I know the name is not the bet...I took it from the Java examples in the Wikipedia article about DCLP). Foo is the Singleton container.
EDIT 2:
Because it seems to be a little bit misunderstanding that Foo is not a static class and how it is used, here an example of the usage:
static Foo foo;
.
.
.
foo.getHelper()->doSomething();
.
.
.
The reason that Foo's members are not static is simply that I was able to create/destroy the mutex and the TLS in the constructor/destructor. If a RAII version of a C++ mutex / TLS class is used Foo can easily be switched to be static.