Oracle Solaris Studio 12.2:线程分析器用户指南

2.6.3 使用双检锁的程序

单件可确保在整个程序中只有一个特定类型的对象存在。双检锁是在多线程应用程序中对单件进行初始化的一种常见的有效方法。以下代码将说明这样的实现。

 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。因此,所有线程将一致地读取它们。如果未使用内存屏障,此编程方法将失效。