C++11 单例类实现
单例类:
(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 单例类实现的更多相关文章
- c++:自己动手实现线程安全的c++单例类
前段时间使用c++做项目开发,需要根据根据配置文件路径加载全局配置文件,并对外提供唯一访问点.面对这样一个需求,自然的就想到了使用单例模式来创建一个单例配置对象,供外部调用.一开始想使用boost中自 ...
- 游戏设计模式——C++单例类
前言: 本文将探讨单例类设计模式,单例类的懒汉模式/饿汉模式,单例类的多线程安全性,最后将利用C++模板减少单例类代码量. 本文假设有一个Manager管理类,并以此为探究单例类的设计模式. 懒汉模式 ...
- java单例类/
java单例类 一个类只能创建一个实例,那么这个类就是一个单例类 可以重写toString方法 输出想要输出的内容 可以重写equcal来比较想要比较的内容是否相等 对于final修饰的成员变量 一 ...
- iOS中编写单例类的心得
单例 1.认识过的单例类有哪些: NSUserDefaults.NSNotificationCenter.NSFileManager.UIApplication 2.单例类 单例类某个类在代码编写时使 ...
- 如何防止JAVA反射对单例类的攻击?
在我的上篇随笔中,我们知道了创建单例类有以下几种方式: (1).饿汉式; (2).懒汉式(.加同步锁的懒汉式.加双重校验锁的懒汉式.防止指令重排优化的懒汉式); (3).登记式单例模式; (4).静态 ...
- 0013 Java学习笔记-面向对象-static、静态变量、静态方法、静态块、单例类
static可以修饰哪些成员 成员变量---可以修饰 构造方法---不可以 方法---可以修饰 初始化块---可以修饰 内部类(包括接口.枚举)---可以修饰 总的来说:静态成员不能访问非静态成员 静 ...
- 设计模式(java) 单例模式 单例类
·单例类 单实例类,就是这个类只能创建一个对象,保证了对象实例的唯一性. 1.单例模式( Singleton Pattern) 是一个比较简单的模式, 其定义如下:Ensure a class has ...
- [转]单例模式——C++实现自动释放单例类的实例
[转]单例模式——C++实现自动释放单例类的实例 http://www.cnblogs.com/wxxweb/archive/2011/04/15/2017088.html http://blog.s ...
- iOS - OC SingleClass 单例类
前言 单例对象能够被整个程序所操作.对于一个单例类,无论初始化单例对象多少次,也只能有一个单例对象存在,并且该对象是全局的,能够被整个系统访问到. 特点: 在内存中只有一个实例 提供一个全局的访问点 ...
随机推荐
- office web apps 部署-搭建域控服务器
开始第一条先说注意事项:我所配置的环境是用了三台2012server虚拟机,三台虚拟机必须要加下域控,而且登录操作的时候必须以域账号登录,否则测试不通过!在笔记本上搭建了两个虚拟机(window se ...
- JavaScript中var变量引用function与直接声明function
今天在h5开发app的过程中遇到了一个js问题,function的执行问题 在js中声明函数function有这两种方法 var A=function(){...} 或者 function A(){. ...
- 蓝桥杯-n级台阶-java
/* (程序头部注释开始) * 程序的版权和版本声明部分 * Copyright (c) 2016, 广州科技贸易职业学院信息工程系学生 * All rights reserved. * 文件名称: ...
- spring、spring mvc、mybatis框架整合基本知识
学习了一个多月的框架知识了,这两天很想将它整合一下.网上看了很多整合案例,基本都是基于Eclipse的,但现在外面公司基本都在用Intellij IDEA了,所以结合所学知识,自己做了个总结,有不足之 ...
- 0基础搭建Hadoop大数据处理-环境
由于Hadoop需要运行在Linux环境中,而且是分布式的,因此个人学习只能装虚拟机,本文都以VMware Workstation为准,安装CentOS7,具体的安装此处不作过多介绍,只作需要用到的知 ...
- OC中NSFileManager
NSFileManager介绍 NSFileManager是用来管理文件系统的 它可以用来进行常见的文件\文件夹操作(拷贝.剪切.创建等) NSFileManager使用了单例模式singleton ...
- python 小程序—三级菜单—循环和字典练习
程序中利用多级字典来存储三级菜单, 通过一系列while循环和for循环,实现了三级菜单的查询,选择,退回上级菜单,退出程序几个功能. 缺点:程序语句过于重复,效率低. #-*-coding:utf- ...
- Gephi安装
Gephi for mac https://gephi.org/users/download/ 在官网上下载gephi-0.9.1-macos.dmg双击拖到Application里面就好了,注意有的 ...
- PHP导出生成CSV文件
composer 用起来是非常方便的 所以我是依赖composer来做的包管理 1.先安装composer 自行百度一下composer安装以及使用 2.用composer下载安装office包即可 ...
- UITextView 实现链接点击事件
UILabel通过富文本可以实现图文混排,但是想要实现文字的点击效果好像不容易实现,这里有2种方法可以达到效果 YYLabel -->YYText框架 参考我之前的博客:http://www.c ...