Information Technology Reference
In-Depth Information
The “optimization” is to avoid acquiring the lock if the object has not already been
allocated, but to avoid allocating the object multiple times by acquiring the lock and
rechecking the status before allocating the object:
Singleton*Singleton::pInstance=NULL;
//BUG! Don'tdothis!
Singleton*Singleton::instance(){
if(pInstance==NULL){
lock->Acquire();
if(pInstance==NULL){
pInstance=newInstance();
classSingleton{
public:
staticSingleton*instance();
Locklock;
...
private:
staticSingleton*pInstance;
}
lock->Release();
};
}
returnpInstance;
}
Singleton.h header file Singleton.cc implementation file
Although the intuition is appealing, this code does not work. The problem is that
the statement pInstance=newInstance() is not an an atomic operation; in fact, it
comprises at least three steps:
1. Allocate memory for a Singleton object
2. Initialize the Singleton object's memory by running the constructor
3. Make pInstance point to this newly constructed object
The problem is that, modern compilers and hardware architectures can reorder
these events. Thus, it is possible for thread 1 to execute the first step and then the
third step; then thread 2 can call instance() , see that pInstance is non-null, return it,
and begin using this object before thread 1 initializes it.
Discussion. This is just an example of dangers that lurk when you try to elide locks;
the lesson applies more broadly. This example is extremely simple—fewer than 10 lines
of code with very simple logic—yet a number of published solutions have ben wrong. For
example, Meyers and Alexandrescu's “C++ and the Perils of Double-Checked Locking”
notes, some tempting solutions using temporary variables and the volatile keyword
don't work. 7 Bacon et al.'s “The 'Double-Checked Locking is Broken' Declaration” dis-
cusses a wide range of non-working solutions in Java.
This type of optimization is risky and often does not end up providing significant
performance gains in program. Most programmers should not consider them. Even
expert programmers should habitually stick to simpler programming patterns like the
ones we discuss in the body of the text and should consider optimizations like double-
checked locking only rarely and only when performance measurements and profiling
indicate that the optimizations will matter for overall performance.
7 There are (non-portable) solutions in C/C++, but we won't give them here. If you
want to try these advanced techniques, then you should read the literature for more in-depth
discussions so that you deeply understand the issues and why various appealing \solutions"
fail.
Search WWH ::




Custom Search