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 单例类
前言 单例对象能够被整个程序所操作.对于一个单例类,无论初始化单例对象多少次,也只能有一个单例对象存在,并且该对象是全局的,能够被整个系统访问到. 特点: 在内存中只有一个实例 提供一个全局的访问点 ...
随机推荐
- 简单明了查看内存使用和ubuntu的版本号及位数
1.查看ubuntu的版本号:cat /etc/issue 2.查看系统是32位的还是64位:getconf LONG_BIT 3.查看内存使用 free free命令可以用来查看系统内存使用情况,- ...
- TPshop入门大纲
笔记大纲: tpshop目录结构 功能模块 函数库 重要配置 助手函数 插件 模板 1.TPshop目录结构 看这个图,目录结构一目了然. 下面要讲的内容也是根据这个图展开的. 2.功能模块 前几天刚 ...
- httpd配置ResponseHeader
今天遇到一个问题:我把项目编译后的静态文件发布到开发机上,开发机使用httpd启的静态文件服务,页面的访问是在特制的壳浏览器里面,我更新了代码后,发现页面被缓存了,找到壳的RD联调了一下,发现我的主页 ...
- A*算法的理解与简单实现
基本定义 一种寻路算法,特点是:启发式的,效率高,基本思路比较简单. 用途 寻路.在指定的地图上,考虑到地图上的移动代价,找到最优的路径. 核心概念 开表,闭表,估值函数. 开表 开表,记录了当前需要 ...
- 前端魔法堂:onsubmit和submit事件处理函数怎么不生效呢?
前言 最近在用Polymer增强form,使其支持表单的异步提交,但发现明明订阅了onsubmit和submit事件,却怎么也触发不了.下面我们将一一道来. 提交表单的方式 表单仅含一个以下的元素时 ...
- jQuery选择器的优点
jQuery选择器的优点 相信小伙伴们对选择器并不陌生,从css1到css3的选择器有很多,但是JQuery都能完美的支持,而且API操作起来也特别方便好用,在很大程度上精简了代码,节约了很多性能.那 ...
- Linux-vim学习入门
1.前言 vi/vim是linux中很重要的文本编辑器.我第一次使用这个编辑器时,很不习惯,甚至都不知道如何移动光标和插入字符.慢慢地经过学习,才知道如何使用vi/vim. vi/vi ...
- 由"永恒之蓝"病毒而来的电脑科普知识
永恒之蓝病毒事件: 继英国医院被攻击,随后在刚刚过去的5月12日晚上20点左右肆虐中国高校的WannaCry勒索事件,全国各地的高校学生纷纷反映,自己的电脑遭到病毒的攻击,文档被加密,壁纸遭到篡改,并 ...
- dubbo高级配置学习
启动时检查 可以通过check="false"关闭检查,比如,测试时,有些服务不关心,或者出现了循环依赖,必须有一方先启动. 关闭某个服务的启动时检查:(没有提供者时报错) < ...
- CountDownLatch, CyclicBarrier and Semaphore
Reference: [1] http://shazsterblog.blogspot.co.uk/2011/12/comparison-of-countdownlatch.html CountDow ...