单例类:

(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. js事件触发(一)

    今日和一位前端童鞋聊了下js触发事件的两种形式: 第一种在jsp/vm上做类似onClick=functionName()的触发:另一种是在js文件中增加对应节点的监听事件触发.前者页面掺杂了js的内 ...

  2. Linux上bash的部分基础特性:

    命令补全: tab shell程序在接收到用户执行命令的请求,分析完成后,最左侧的字符串会被当做命令 命令查找机制: 查找内部命令: 根据PATH环境变量中设定的目录,自左而右逐个搜索目录下的文件名 ...

  3. LeetCode:60. Permutation Sequence,n全排列的第k个子列

    LeetCode:60. Permutation Sequence,n全排列的第k个子列 : 题目: LeetCode:60. Permutation Sequence 描述: The set [1, ...

  4. springcloud(四):熔断器Hystrix

    说起springcloud熔断让我想起了去年股市中的熔断,多次痛的领悟,随意实施的熔断对整个系统的影响是灾难性的,好了接下来我们还是说正事. 熔断器 雪崩效应 在微服务架构中通常会有多个服务层调用,基 ...

  5. php.ini 文件中配置的意义注释

    ;;;;;;;;;;;;;;;;;;;; About php.ini   ;  //关于php;;;;;;;;;;;;;;;;;;;; PHP's initialization file, gener ...

  6. carryLess小笔记001_Java中16进制与字符串之间的相互转换

    笔者前几日在开服过程中需要将字符串转化成为16进制的字符串,在网上找到了一些方法尝试之后,均发现存在一个问题-->字符串转为16进制后再转回来,英文正常,中文出现乱码 经过考虑决定通过以下方式进 ...

  7. Vue常用经典开源项目汇总参考-海量

    Vue常用经典开源项目汇总参考-海量 Vue是什么? Vue.js(读音 /vjuː/, 类似于 view) 是一套构建用户界面的 渐进式框架.与其他重量级框架不同的是,Vue 采用自底向上增量开发的 ...

  8. UITextField关闭自动联想功能

    在textField输入内容时,如果内容为英文,输入的英文如果不正确的单词就是有红色的线报警,关闭英文自动联想功能 self.autocorrectionType = UITextAutocorrec ...

  9. 树莓派安装FLASK服务;并在端网页读取 GPIO状态和系统时间

    做过一些物联网的作品:因为不想一直做APP来控制,因为不能每个人都去下载你自己做的APP,浏览器大家都是有的:那么每个人通过浏览器WEB来访问我们服务器,岂不是很简单和方便,采用flask+pytho ...

  10. 线程机制、CLR线程池以及应用程序域

    最近在总结多线程.CLR线程池以及TPL编程实践,重读一遍CLR via C#,比刚上班的时候收获还是很大的.还得要多读书,读好书,同时要多总结,多实践,把技术研究透,使用好. 话不多说,直接上博文吧 ...