No, you cannot even assume that foo = p; is atomic. Perhaps it can load 16 bits of a 32-bit pointer, and then swap it before loading the rest.
If at this moment another thread is Instance() and calls Instance() , you are frying, because the pointer foo invalid.
For true security, you will have to protect the entire testing and tuning mechanism, although this means using mutexes even after creating the pointer. In other words (and I assume that scoped_lock() will release the lock when it goes out of scope here (I have little experience with Boost)), something like:
Foo& Instance() { scoped_lock lock(mutex); if (foo != 0) foo = new Foo(); return *foo; }
If you do not want to use mutexes (for performance reasons, presumably), then the option that I used in the past is to create all singletones before the threads begin.
In other words, if you have this control (you cannot), just instantiate each singleton in main before starting other threads. Then do not use the mutex at all. At this point, you will not have problems with threads, and you can simply use the canonical don't-care-about-threads-at-all version:
Foo& Instance() { if (foo != 0) foo = new Foo(); return *foo; }
And yes, it makes your code more dangerous for people who couldnβt bother to read your API documents, but (IMNSHO) they deserve everything they get :-)
source share