1、DCLP与单例
DCLP即Double-Checked Lock Pattern,最常见的一种写法是用于单例模式之中,例如:
Singleton* Singleton::instance() {
if (pInstance == 0) { // 1st test
Lock lock;
if (pInstance == 0) { // 2nd test
pInstance = new Singleton;
}
}
return pInstance;
}
但是,这样写是有问题的,原因在于pInstance = new Singleton,这条语句实际是由三部分构成的:
1、对Singleton对象分配内存
2、调用Singleton的构造函数
3、把这块内存的地址赋给pInstance
在多线程模型下,有可能会发生指令重排序,即2和3有可能会被调换,那么如果在一个线程中3在2前发生,另一个线程又恰好执行到了代码中 “1st test”的部分,那么该线程会直接返回一个未执行构造函数的Singleton对象,因此导致的错误的发生,这一点,Scott Meyers和Andrei Alexandrescu专门写过一篇论文讨论过:C++ and the Perils of Double-Checked Locking
2、内存结构与指令重排序
先来看一张典型的内存体系的图:
从上往下看,计算机内存由 寄存器->Memory Ordering Buffer->L1缓存->L2缓存->L3缓存->主内存->硬盘组成,自顶向下遵循的原则为:
越靠近顶端的容量越小,速度越快
其中,(含)L2缓存而上的都是CPU内部结构,L3缓存则为同一插