“臭名昭著“ 的双检查锁双检查锁即锁前检查一次锁后检查一次。进而避免了无脑上锁对运行时候的性能损耗。有朋友可能对双检查锁的逻辑有疑惑或不解我们可以做两个假设假设取消第一个 if 判断这就变成了上文提到的无脑上锁的情况假设取消第二个 if 判断这又变成了上面单线程版本中可能多次进入最外层 if 的情况因此这两次检查都是必不可少的。// 双检查锁的最初版本 static Singleton* instance() { if (nullptr s_instancePtr) { std::lock_guardstd::mutex lock(s_mutex); if (nullptr s_instancePtr) { s_instancePtr new Singleton(); } } return s_instancePtr; }到了这里我们的问题都解决了吗答案是并非解决甚至仍有巨大隐患。具体原因需要往更深层次去探讨。我们脱离代码层面考虑 CPU 的指令层次会出现一个问题指令重排 reorder简单分析下::operator new();这个操作new 的理想状态下可以分为三个步骤①. 申请内存②. 执行构造器③. 给调用方返回地址但是在实际的中经过了指令重排可能会出现 ①③② 这种排列。一旦出现了这种情况可能会对程序造成不可估计的后果。能解决这种问题吗很抱歉这已经不是普通程序员能涉及的层面了需要各个语言标准和编译器方来处理。注意这不是单门语言的问题而是属于计算机底层的问题任何语言都会出现该问题。
一文看清:“臭名昭著“ 的双检查锁
“臭名昭著“ 的双检查锁双检查锁即锁前检查一次锁后检查一次。进而避免了无脑上锁对运行时候的性能损耗。有朋友可能对双检查锁的逻辑有疑惑或不解我们可以做两个假设假设取消第一个 if 判断这就变成了上文提到的无脑上锁的情况假设取消第二个 if 判断这又变成了上面单线程版本中可能多次进入最外层 if 的情况因此这两次检查都是必不可少的。// 双检查锁的最初版本 static Singleton* instance() { if (nullptr s_instancePtr) { std::lock_guardstd::mutex lock(s_mutex); if (nullptr s_instancePtr) { s_instancePtr new Singleton(); } } return s_instancePtr; }到了这里我们的问题都解决了吗答案是并非解决甚至仍有巨大隐患。具体原因需要往更深层次去探讨。我们脱离代码层面考虑 CPU 的指令层次会出现一个问题指令重排 reorder简单分析下::operator new();这个操作new 的理想状态下可以分为三个步骤①. 申请内存②. 执行构造器③. 给调用方返回地址但是在实际的中经过了指令重排可能会出现 ①③② 这种排列。一旦出现了这种情况可能会对程序造成不可估计的后果。能解决这种问题吗很抱歉这已经不是普通程序员能涉及的层面了需要各个语言标准和编译器方来处理。注意这不是单门语言的问题而是属于计算机底层的问题任何语言都会出现该问题。