Cpp Double Check Lock

From DoubleCheckedLockingIsBroken

The above discussion applies to JavaLanguage, but double-checked locking poses problems for CeePlusPlus as well. See http://groups.google.com/groups?selm=MPG.191d9257dfa5ebf79896db%40news.hevanet.com.

Here's what I use in an embedded system that uses dozens of threaded singletons and has worked fine for many years under very difficult tests and deployment conditions.

Note that there's a separate Service class so that singletonness is separate from the class.

 YourClass*  YourClassService::mpSingleton;
 YourMutexYourClassService::mProtection;

YourClass* YourClassService::Singleton() { // First check to see if the singleton has been created. // if (mpSingleton == 0) { // Block all but the first creator. // YourLockGuard lock(mProtection);

// Check again just in case someone had created it // while we were blocked. // if (mpSingleton == 0) { // Create the singleton YourClass object. It's assigned // to a temporary so other accessors don't see // the singleton as created before it really is. // YourClass* inprocess_singleton= new YourClass();

// The singleton is created successfully so assign it. // mpSingleton= inprocess_singleton;

}// still not created

}// not created

return mpSingleton;

}// Singleton


That doesn't really prove anything -- most of the problems occur on multiprocessor systems with weak memory models, and you haven't said what architecture, compiler, or optimization level you were using.

And what would that "prove" sufficiently that you couldn't marginalize it with more qualifiers?

Read the DoubleCheckedLockingIsBroken papers again: the point isn't that double checked locking is broken, the point is that it cannot be fixed. Really. Really and Truely. It only works if written with complete knowledge of both the compiler and the platform, at which point you are literally writing at the level of machine code. Do you really want to keep schematics to every CPU series you plan on running your software on? --WilliamUnderwood

No, the paper says double checked locking cannot be fixed given the guarantees the Java memory model gives you (and I think cpp doesn't give them either). It can work if the right guarantees are provided, which is something I believe the new java memory model does (however, in the new model DoubleCheckedLocking is no longer as efficient as it used to be). I don't know if cpp gives enough guarantees to make it work, but at least the code fragment should be using some 'volatile's to work. As cpp doesn't have any notion of threads, I suppose it doesn't give the nescessary guarantees. I consider it a bug in the language specification.

''If you are saying you can't write code in C that works everywhere then that is known. If you let that stop you from writing code that works on 99% of all platforms that is up to you. My code has worked on a lot of platforms. That is good enough for me.''

It shouldn't be. You don't know that it has "worked"; lock bugs are often low frequency, and hence difficult/impossible to find by testing, including using the customer as your tester. If a program crashes or gets a wrong answer or behaves in a peculiar way once every 2 or 3 months, you may never know it, but it's still a bug.

Here we have a situation that is known not to be workable. It's unhealthy to ignore a known problem.

Some of the discussion emphasizes compiler optimizations and/or variations in cpu, but the problem is worse than that; it may happen on essentially all platforms with all cpus, all compilers, all optimization levels, any load level, and any number of threads, simply with varying frequency of occurrence. You won't know otherwise unless you can prove (not test!!) that it works in some given circumstance, and it's pretty predictable that not a soul in the world will do that. Anyone who cared enough would just switch to a safer technique.

So in the face of that, "works well enough for me" means "I don't mind bugs if they don't pop up often", which isn't a very defensible attitude unless e.g. accompanied by some additional argument concerning cost tradeoffs for some particular project, a difficult argument to win, considering the existing discussion about the relatively low cost of switching to a known-correct method.


As cpp doesn't have any notion of threads -- really? Then what is the purpose of the "volatile" keyword? volatile simply means that the compiler is not allowed to assume that the contents of a location will not change out from under it. Threads aren't the only reason this can happen (think memory-mapped I/O). In fact, threads (as we know them) didn't exist on the machines that first implemented C. C and C++ really, truly have no notion of threads. --TimLesher

the relatively low cost of switching to a known-correct method. You have stumbled upon one of my pet peeves: alluding to something that you claim exists, but without enough details to allow me find it -- or even recognize it, if I am lucky enough to stumble across it.

What "known-correct method" are you talking about?

-- DavidCary


The "known-correct" methods that I'm aware of are:


EditText of this page (last edited February 13, 2007) or FindPage with title or text search