在C++和Double-Checked Locking的Perils中,有一些persudo代码可以正确地实现模式,这是作者建议的.见下文,
Singleton* Singleton::instance () {
Singleton* tmp = pInstance;
... // insert memory barrier (1)
if (tmp == 0) {
Lock lock;
tmp = pInstance;
if (tmp == 0) {
tmp = new Singleton;
... // insert memory barrier (2)
pInstance = tmp;
}
}
return tmp;
}
Run Code Online (Sandbox Code Playgroud)
我只是想知道第一个内存屏障是否可以在return语句的正上方移动?
编辑:另一个问题:在链接文章中,引用vidstige
从技术上讲,您不需要完全双向障碍.第一道屏障必须防止Singleton构造的向下迁移(通过另一个线程); 第二个障碍必须阻止pInstance初始化的向上迁移.这些被称为"获取"和"释放"操作,并且可以产生比硬件(例如Itainum)上的完全障碍更好的性能.
它说第二个障碍不需要是双向的,那么如何防止pInstance的赋值在该障碍之前被移动?即使第一个障碍可以阻止向上迁移,但另一个线程仍然有机会看到未初始化的成员.
编辑:我想我几乎明白第一道屏障的目的.正如sonicoder所指出的,当if返回true时,分支预测可能导致tmp为NULL.为了避免这个问题,必须有一个获取障碍,以防止在读取if之前读取tmp.
第一道屏障与第二道屏障配对以实现同步关系,因此它可以向下移动.
编辑:对于那些对这个问题感兴趣的人,我强烈建议阅读memory-barriers.txt.