单例类:

(1) 单例类保证全局只有一个唯一的实例对象。

(2) 单例类保证只有唯一的接口获取这唯一实例。

非线程安全的单例类举例:

 class CSingleton
{
public:
~CSingleton(){}
static CSingleton * getInstance()
{
if (m_instance == nullptr)
{
m_instance = new CSingleton;
}
return m_instance;
}
static void delInstance()
{
if (m_instance)
{
delete m_instance;
m_instance = nullptr;
}
}
void print()
{
std::cout << "print test" << std::endl;
}
private:
CSingleton(){}
CSingleton & operator=(const CSingleton & ) = delete;
CSingleton(const CSingleton &) = delete;
private:
static CSingleton * m_instance;
}; CSingleton * CSingleton::m_instance = nullptr;

上述单例类面对多线程并发访问时会出错。

看如下线程安全的单例类(非C++11实现)

 class CSingleton
{
public:
~CSingleton() {}
static CSingleton * getInstance()
{
if (m_instance == nullptr)
{
std::lock_guard<std::mutex> lgd(m_mt);
if (m_instance == nullptr)
{
m_instance = new CSingleton;
}
}
return m_instance;
}
static void delInstance()
{
std::lock_guard<std::mutex> lgd(m_mt);
if (m_instance)
{
delete m_instance;
m_instance = nullptr;
}
}
void print()
{
std::cout << "print test" << std::endl;
}
private:
CSingleton() {}
CSingleton & operator=(const CSingleton & ) = delete;
CSingleton(const CSingleton &) = delete;
private:
static CSingleton * m_instance;
static std::mutex m_mt;
}; CSingleton * CSingleton::m_instance = nullptr;
std::mutex CSingleton::m_mt;

当然绝对的线程安全还是有问题,因为C++创建对象时,会执行1、分配内存,2 调用构造,3 赋值操作三步操作,然而现代CPU和编译器高并发下可能

会进行乱序重排操作,因而创建对象new CSingleton的第2步可能会晚于第3步进行指令调用,因而导致出现未定义的的行为。

举例:

线程A : getInstance 判断 instance是否为空,为空则

线程A : 分配内存  此时CPU乱序指令重排,赋值操作提前

线程B : getInsnace 判断instance是否为空,非空,则返回

线程B : 使用了未初始化的instacne 出现未定义行为。

线程A : 调用构造函数对instance初始化。

因此要解决上述问题需要引入内存栅栏来确保指令运行的同步性。在CPU指令重排的前提下保持数据的一致性。

C++11支持线程安全的单例类:

C++11的单例模式的实现

 class CSingleton
{
public:
~CSingleton() {}
static CSingleton & getInstance()
{
static CSingleton m_instance;
return m_instance;
}
void print()
{
std::cout << "print test" << std::endl;
}
};

返回静态局部对象的引用,C++11中是线程安全的。

验证一下:

 class CStatic
{
public:
CStatic()
{
std::cout << "construct begin" << std::endl;
Sleep();
std::cout << "construct end" << std::endl;
}
void print()
{
std::cout << "print" << std::endl;
std::cout << s_num++ << std::endl;
}
static int s_num;
static std::mutex s_mt;
};
 int CStatic::s_num = ;
std::mutex CStatic::s_mt; //
void thread_func()
{
static CStatic st;
st.print();
} int main()
{
std::vector<std::thread> vecThread;
for (auto i = ; i< ; i++)
{
vecThread.push_back(std::thread(thread_func));
}
for (auto i = ; i< ; i++)
{
vecThread[i].join();
}
//
system("pause");
return ;
}

首先我们创建一个CStatic类,然后创建8个线程来启动thread_func(),thread_func()初始化了一个静态CStatic对象,(静态局部变量仅被初始化一次)

然后接着运行。我们发现,当首个线程初始化CStatic时,其他线程都是被阻塞的,从构造函数的begin和end中可以看到,我们故意让其停留5s,

如下图,其他线程都是在st被初始化之后才运行。

所以CStatic静态局部对象被构造的过程中是线程安全的,但是其拥有的成员变量则不是线程安全的。

因此我们增加个简单的锁,

 class CStatic
{
public:
CStatic()
{
std::cout << "construct begin" << std::endl;
Sleep();
std::cout << "construct end" << std::endl;
}
void print()
{
std::lock_guard<std::mutex> lgd(s_mt);
std::cout << "print" << std::endl;
std::cout << s_num++ << std::endl;
}
static int s_num;
static std::mutex s_mt;
};

 

C++11 单例类实现的更多相关文章

  1. c++:自己动手实现线程安全的c++单例类

    前段时间使用c++做项目开发,需要根据根据配置文件路径加载全局配置文件,并对外提供唯一访问点.面对这样一个需求,自然的就想到了使用单例模式来创建一个单例配置对象,供外部调用.一开始想使用boost中自 ...

  2. 游戏设计模式——C++单例类

    前言: 本文将探讨单例类设计模式,单例类的懒汉模式/饿汉模式,单例类的多线程安全性,最后将利用C++模板减少单例类代码量. 本文假设有一个Manager管理类,并以此为探究单例类的设计模式. 懒汉模式 ...

  3. java单例类/

    java单例类  一个类只能创建一个实例,那么这个类就是一个单例类 可以重写toString方法 输出想要输出的内容 可以重写equcal来比较想要比较的内容是否相等 对于final修饰的成员变量 一 ...

  4. iOS中编写单例类的心得

    单例 1.认识过的单例类有哪些: NSUserDefaults.NSNotificationCenter.NSFileManager.UIApplication 2.单例类 单例类某个类在代码编写时使 ...

  5. 如何防止JAVA反射对单例类的攻击?

    在我的上篇随笔中,我们知道了创建单例类有以下几种方式: (1).饿汉式; (2).懒汉式(.加同步锁的懒汉式.加双重校验锁的懒汉式.防止指令重排优化的懒汉式); (3).登记式单例模式; (4).静态 ...

  6. 0013 Java学习笔记-面向对象-static、静态变量、静态方法、静态块、单例类

    static可以修饰哪些成员 成员变量---可以修饰 构造方法---不可以 方法---可以修饰 初始化块---可以修饰 内部类(包括接口.枚举)---可以修饰 总的来说:静态成员不能访问非静态成员 静 ...

  7. 设计模式(java) 单例模式 单例类

    ·单例类 单实例类,就是这个类只能创建一个对象,保证了对象实例的唯一性. 1.单例模式( Singleton Pattern) 是一个比较简单的模式, 其定义如下:Ensure a class has ...

  8. [转]单例模式——C++实现自动释放单例类的实例

    [转]单例模式——C++实现自动释放单例类的实例 http://www.cnblogs.com/wxxweb/archive/2011/04/15/2017088.html http://blog.s ...

  9. iOS - OC SingleClass 单例类

    前言 单例对象能够被整个程序所操作.对于一个单例类,无论初始化单例对象多少次,也只能有一个单例对象存在,并且该对象是全局的,能够被整个系统访问到. 特点: 在内存中只有一个实例 提供一个全局的访问点 ...

随机推荐

  1. 蓝桥杯-买不到的数目-java

    /* (程序头部注释开始) * 程序的版权和版本声明部分 * Copyright (c) 2016, 广州科技贸易职业学院信息工程系学生 * All rights reserved. * 文件名称: ...

  2. 全球移动互联网大会gmic 2017为什么值得参加?

    长城会CEO郝义认为,"科学产业化将会推动科学复兴,"而本次GMIC 北京 2017也将首次引入了高规格科学家闭门峰会,专门设置G-Summit全球科学创新峰会,以"科学 ...

  3. 设计模式的征途—6.建造者(Builder)模式

    建造者模式又称为生成器模式,它是一种较为复杂.使用频率也相对较低的创建型模式.建造者模式为客户端返回的不是一个简单的产品,而是一个由多个部件组成的复杂产品.因为,没有人买车会只买一个方向盘或者轮胎,大 ...

  4. 解决mysql 服务无法启动问题:Can't find messagefile 'D:\ ools\mysql-5.6.25-winx64\share\errmsg.sys'

    右击我的电脑-->管理,查看Window日志里的应用程序,发现报错. 仔细检查一下my.ini的配置,确保路径正确,楼主的目录如下: 关键的一步,查看my.default文件,加入这样一句:sq ...

  5. [刷题]ACM/ICPC 2016北京赛站网络赛 第1题 第3题

    第一次玩ACM...有点小紧张小兴奋.这题目好难啊,只是网赛就这么难...只把最简单的两题做出来了. 题目1: 代码: //#define _ACM_ #include<iostream> ...

  6. 升讯威微信营销系统开发实践:(5) Github 源码:微信接口的 .NET 封装。

    微信开发系列教程,将以一个实际的微信平台项目为案例,深入浅出的讲解微信开发.应用各环节的实现方案和技术细节. 本系列教程的最终目标是完成一个功能完善并达到高可用性能指标的微信管理软件,所以除了与微信本 ...

  7. 响应式web-媒体查询

    响应式web-媒体查询 媒体查询是一个将很多响应式概念和工具连接在一起的粘合剂.这些查询语句都是简单但是功能很强大的,它们允许我们检测设备属性,定义规则,并根据规则等的不同加载不同的 CSS 属性.例 ...

  8. .net后台获取DataTable数据,转换成json数组后传递到前台,通过jquery去操作json数据

    一,后台获取json数据 protected void Page_Load(object sender, EventArgs e){  DataTable dt = DBhepler.GetDataT ...

  9. redis 清空缓存

    redis 清空缓存 Redis 命令: flushall --> 清空整个 Redis 服务器的数据(删除所有数据库的所有 key ) flushdb --> 清空当前数据库中的所有 k ...

  10. python中的JSON(1)

    很多程序都要求用户输入某种信息, 例如:   让用户存储游戏首选项或提供要可视化的数据,程序把用户的信息存储在列表和字典等数据结构中, 用户关闭程序时,我们几乎总要保存他们提供的信息: 如何保存-- ...