单件可确保在整个程序中只有一个特定类型的对象。双检锁是一种常用的有效方法,用于在多线程应用程序中初始化单件。以下代码说明这样的实现。
100 class Singleton {
101 public:
102 static Singleton* instance();
103 ...
104 private:
105 static Singleton* ptr_instance;
106 };
...
200 Singleton* Singleton::ptr_instance = 0;
...
300 Singleton* Singleton::instance() {
301 Singleton *tmp = ptr_instance;
302 memory_barrier();
303 if (tmp == NULL) {
304 Lock();
305 if (ptr_instance == NULL) {
306 tmp = new Singleton;
307 memory_barrier();
308 ptr_instance = tmp;
309 }
310 Unlock();
311 }
312 return tmp;
313 }
ptr_instance 的读取(第 301 行)有意不受锁的保护。这使检查可以确定在多线程环境中是否已有效地实例化单件。请注意,在第 301 行上的读取和第 308 行上的写入之间存在对 ptr_instance 变量的数据争用,但是程序可正常工作。不过,编写允许数据争用的正确程序是一项艰难的任务。例如,在上面的双检锁代码中,第 302 行和第 307 行上对 memory_barrier() 的调用用于确保按正确的顺序设置和读取单件和 ptr_instance。因此,所有线程将一致地读取它们。如果未使用内存屏障,则此编程方法将失效。