为什么说DCLP不是线程安全的

DCLP(Double Checked Locking Pattern),即双检锁模式:

class Foo {
public:
static Foo* getInstance() noexcept {
if (nullptr == s_pInstance) {
std::lock_guard<std::mutex> lock(s_mutex);
if (nullptr == s_pInstance) {
s_pInstance = new Foo();
}
} return s_pInstance;
} private:
static Foo* volatile s_pInstance;
static std::mutex s_mutex;
};

在C++中,volatile关键字只保证数据的可见性,并不保证数据的一致性。所以当外面的判断s_pInstance非空的时候,由于可能的指令重排,这时对象可能还没有真正的构造好,使得程序无法按照预定的行为执行。

新标准中更好的解决方案

在C++中,静态局部变量的初始化发生在程序第一次执行到变量声明的地方:

static Foo* getInstance() {
static Foo s_instance;
return &s_instance;
}

在C++98中,并没有考虑线程安全的问题,只是简单地用一个条件判断来实现该语义:

static bool s_initialized = false;
static char s_buf[sizeof(Foo)]; static Foo* instance()
{
if (!s_initialized) {
s_initialized = true;
new (s_buf) Foo();
} return (reinterpret_cast<Foo*>(s_buf));
}

C++11中定义了线程安全的行为,如下是标准草案的6.7节内容:

such a variable is initialized the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization. If the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration. If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization. If control re-enters the declaration recursively while the variable is being initialized, the behavior is undefined.

  • 若初始化抛出异常将继续保持未初始化状态
  • 若正在初始化,其它运行初始化语句线程将被阻塞
  • 若正在初始化的线程递归调用初始化语句行为未定义

C++中线程安全单例模式的正确实现方式的更多相关文章

  1. java中线程池的几种实现方式

    1.线程池简介:    多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力.        假设一个服务器完成一项任务所需时间为:T1 创建 ...

  2. SQL语句中 NOT IN 子句的“正确打开方式”

    在写SQL语句的时候,若where条件是判断用户不在某个集合当中,我们习惯使用 where 列名 not in (集合) 子句,这种写法本身没有问题,但实践过程中却发现很多人在写类似的SQL语句时,写 ...

  3. Java 中线程池的 7 种创建方式!

    在 Java 语言中,并发编程都是通过创建线程池来实现的,而线程池的创建方式也有很多种,每种线程池的创建方式都对应了不同的使用场景,总体来说线程池的创建可以分为以下两类: 通过 ThreadPoolE ...

  4. java中线程池创建的几种方式

    java中创建线程池的方式一般有两种: 通过Executors工厂方法创建 通过new ThreadPoolExecutor(int corePoolSize, int maximumPoolSize ...

  5. Delphi中线程类TThread实现多线程编程1---构造、析构……

    参考:http://www.cnblogs.com/rogee/archive/2010/09/20/1832053.html Delphi中有一个线程类TThread是用来实现多线程编程的,这个绝大 ...

  6. 转载~kxcfzyk:Linux C语言多线程库Pthread中条件变量的的正确用法逐步详解

    Linux C语言多线程库Pthread中条件变量的的正确用法逐步详解   多线程c语言linuxsemaphore条件变量 (本文的读者定位是了解Pthread常用多线程API和Pthread互斥锁 ...

  7. C#中的线程(中)-线程同步

    1.同步要领 下面的表格列展了.NET对协调或同步线程动作的可用的工具:                       简易阻止方法 构成 目的 Sleep 阻止给定的时间周期 Join 等待另一个线程 ...

  8. Swift中编写单例的正确方式

    在之前的帖子里聊过状态管理有多痛苦,有时这是不可避免的.一个状态管理的例子大家都很熟悉,那就是单例.使用Swift时,有许多方法实现单例,这是个麻烦事,因为我们不知道哪个最合适.这里我们来回顾一下单例 ...

  9. 转发 Delphi中线程类TThread 实现多线程编程

    Delphi中有一个线程类TThread是用来实现多线程编程的,这个绝大多数Delphi书藉都有说到,但基本上都是对TThread类的几个成员作一简单介绍,再说明一下Execute的实现和Synchr ...

随机推荐

  1. CVE-2020-0796(永恒之黑)漏洞复现

    声明:仅供学习与参考,请勿用于非法用途(后果自负) 一.影响范围(需关闭 Win10 防火墙): Windows 10 Version 1903 for 32-bit Systems Windows ...

  2. vue 实现原理及简单示例实现

    目录 相关html代码,用于被解析绑定数据 observer代码 Dep代码 Watcher 代码 Compile 代码 vue 简要构造函数 创建vue实例 结语 主要理解.实现如下方法: Obse ...

  3. oracle数据处理之sql loader(三)

    数据装载 sql loader(PPT-I-490-498) 14.1 sql*loader:将外部数据(比如文本型)数据导入oracle database.(用于数据导入.不同类型数据库数据迁移) ...

  4. oracle之二归档日志

    归档日志 archivelog 5.1 归档和非归档的区别     1)归档会在日志切换时,备份历史日志,用于OLTP,可以进行冷备份和热备份,可以实现数据库完全恢复.不完全恢复(基于时间点)     ...

  5. [LeetCode] 203. 移除链表元素(链表基本操作-删除)、876. 链表的中间结点(链表基本操作-找中间结点)

    题目 203. 移除链表元素 删除链表中等于给定值 val 的所有节点. 题解 删除结点:要注意虚拟头节点. 代码 class Solution { public ListNode removeEle ...

  6. python中random库的使用

    基本随机函数 计算机产生随机数是需要随机数种子的,例如 给定一个随机数种子,就能利用梅森旋转算法产生一系列随机序列 每一个数都是随机数,只要随机种子相同,产生的随机数和数之间的关系都是确定的 随机种子 ...

  7. java 多线程-4

    十四.sleep方法和wait方法的区别 [面试题] 相同点: 一旦执行方法,都可以使得当前线程进入阻塞状态. 不同点: 两个方法的声明位置不同:Thread类声明sleep():Object类中声明 ...

  8. SpringBoot-02-原理初探之主启动类

    2. 原理初探 2.1 pom.xml 父依赖 主要依赖一个父项目,主要管理项目的资源过滤和插件 <parent> <groupId>org.springframework.b ...

  9. java虚拟机配置

    -XXSurvivorRatio 设置两个survivor和eden的比,8表示两个survivor:eden:2:8.survivor的比例影响新生代向老年代移动的数度.survivor比例越小,新 ...

  10. 容器云平台No.9~kubernetes日志收集系统EFK

    EFK介绍 EFK,全称Elasticsearch Fluentd Kibana ,是kubernetes中比较常用的日志收集方案,也是官方比较推荐的方案. 通过EFK,可以把集群的所有日志收集到El ...