Re: Singleton_pattern and Thread Safety
On 11/12/2010 04:21, Joshua Maurice wrote:
On Dec 10, 8:08 pm, Leigh Johnston<le...@i42.co.uk> wrote:
The problem with the traditional double checked locking pattern is twofold:
1) The "checks" are straight pointer comparisons and for the second
check the pointer may not be re-read after the first check due to
compiler optimization.
2) The initialization of the pointer may be re-ordered by the CPU to
happen before the initialization of the singleton object is complete.
I think you are confusing the checking issue. I am acquiring a lock
before this hidden check of which you speak is made and this check is
not the same as the initial fast pointer check so issue 1 is not a problem.
As far as issue 2 is concerned my version (on VC++ at least) is solved
via my lock primitive which should emit a barrier on RAII construction
and destruction and cause VC++ *compiler* to not re-order stores across
a library I/O call (if I am wrong about this a liberal sprinkling of
volatile would solve it).
I should have stated in the original post that my solution is not
portable as-is but it is a solution for a particular implementation
(which doesn't preclude porting to other implementations). :)
First, you are incorrect about the issues of double checked locking,
and threading in general. I again suggest that you read:
http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf
You are ignoring hardware cache issues and single pipeline reordering
issues.
Also, it may work on the current x86_32 processor, but it probably (?)
won't work on windows on all current available and future hardware.
From the document you keep harping on about:
Singleton* Singleton::instance () {
Singleton* tmp = pInstance;
... // insert memory barrier // (1)
if (tmp == 0) {
Lock lock;
tmp = pInstance;
if (tmp == 0) {
tmp = new Singleton;
... // insert memory barrier // (2)
pInstance = tmp;
}
}
return tmp;
}
My version has the barrier at (2) above which should ensure that stores
for the construction of the singleton object are globally visible before
the store of the pointer. As far as the barrier at (1) is concerned I
am not sure that I need it as I can't have reordered loads of any
pointer (the pointer is only loaded once for the initial fast check).
/Leigh