Re: double-checked locking for singleton pattern
<kse13e@yandex.ru> wrote in message
news:83b09fe9-210c-43eb-9030-ccd6096128ac@m36g2000hse.googlegroups.com...
Hello
After reading the Meyers& Alexandrescu article "C++ and the Perils of
Double-Checked Locking"
(http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf) which
claims that there is no
way of implementing double-checked locking for C++ singletons, I
wonder if the following simple
solution might do the work:
Its not going to work; there is a race-condition.
[...]
The issue which was highlighted in the article is related to the fact
that the line which looks like
pInstance = new Singleton;
can not be used in the Singleton::instance() function since some
compilers may generate code which would assign a value to the
pInstance variable right after allocating memory and BEFORE the
Singleton constructor is executed. It seems that a simple modification
shown above can overcome this problem. Am I wrong? Can someone comment
on that please.
The problem is that your missing a memory barrier after you load from,
and
before you store to the instance pointer. Here is sketch of
high-performance
DCL algorithm that has all the correct barriers in place:
________________________________________________________________
template<typename T>
static T& once() {
static T* g_this = NULL;
static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
1:T* l_this = ATOMIC_LOADPTR_MBDEPENDS(&g_this);
if (! l_this) {
pthread_mutex_lock(&g_lock);
if (! (l_this = g_lock)) {
try {
2: l_this = ATOMIC_STOREPTR_MBRELEASE(&g_this, new T);
} catch (...) {
pthread_mutex_unlock(&g_lock);
throw;
}
}
pthread_mutex_unlock(&g_lock);
}
return *l_this;
}
________________________________________________________________
Line 1 atomically load the shared pointer using trailing data-dependant
load-acquire memory barrier. Line 2 atomically stores to the shared
pointer
using preceding store-release memory barrier:
________________________________________________________________
void* ATOMIC_LOADPTR_MBDEPENDS(void** p) {
void* v;
atomic {
v = *p;
MEMBAR #LoadStore | #LoadDepends;
}
return v;
}
void* ATOMIC_STOREPTR_MBRELEASE(void** p, void* v) {
atomic {
MEMBAR #LoadStore | #StoreStore;
*p = v;
}
return v;
}
________________________________________________________________
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]