(一)简单介绍

单例模式分为两种类型:懒汉模式和饿汉模式。

懒汉模式:在实际类对象被调用时才会产生一个新的类实例,并在之后返回这个实例。多线程环境下,多线程可能会同时调用接口函数创建新的实例,为了防止这种并发情况,需要采用锁机制来保证线程安全性,但由于多线程抢占互斥锁,可能会导致系统的性能瓶颈。

饿汉模式:在程序开始时就会产生一个该类的实例,并在之后返回这个实例。由于在进入主函数之前就由主线程完成了对象的初始化化,所以不用担心多线程问题,也不存在线程安全问题。

(二)懒汉模式举例

#include <iostream>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h> using namespace std; class Singleton
{
private:
Singleton()
{
cout<<"class create"<<endl;
}
static Singleton *m_instance;
static pthread_mutex_t mutex;
class Garbo
{
public:
~Garbo()
{
if (Singleton::m_instance)
{
cout<<"class end"<<endl;
delete Singleton::m_instance;
}
}
};
static Garbo garbo;
public:
static Singleton *getInstance();
// ~Singleton()
// {
// cout<<"class end"<<endl;
// delete m_instance;
// }
}; Singleton* Singleton::m_instance = nullptr;
pthread_mutex_t Singleton::mutex = PTHREAD_MUTEX_INITIALIZER;
Singleton::Garbo Singleton::garbo; Singleton* Singleton::getInstance()
{
if (m_instance == nullptr)
{
pthread_mutex_lock(&mutex);
if (m_instance == nullptr)
m_instance = new Singleton();
pthread_mutex_unlock(&mutex);
}
   return m_instance;
} int main(void)
{
Singleton *singleton = Singleton::getInstance();
return ;
}

上述代码中,在类实例初始化时才调用getInstance创建一个新实例,为了保证线程安全(即互斥),定义互斥锁。将类构造函数定义为private,防止类外部直接调用构造函数。

两次加锁:

假设现在有多个线程欲创建新对象,当前m_instance为nulltpr,进入第一层if,所有线程抢占互斥锁,其中一个线程完成对类实例的创建后解锁并返回,此时唤醒其他线程,当前m_instance已被创建,其他线程将不予以创建新实例,直接返回。从这里也可以看出,由于线程之间对锁的抢占,会有一定的性能开销。

关于单例模式的析构函数:

由于singleton对象是一个static对象,直接delete singleton是不能够调用类析构函数的(注释内容),要想释放m_instance实例,需要内嵌一个class,并初始该静态类成员,当类成员释放时调用其析构函数从而释放m_instance实例。

另一种写法:

测试代码:

class Singleton
{
private:
Singleton(){}
public:
static Singleton* getInstance()
{
Lock(); //not needed after C++0X
static Singleton instacne;
Unlock; //not needed after C++0X
return instance;
}
}

上述在C++0X以后,要求编译器保证内部静态变量的线程安全性,可以不加锁。但在C++0X以前,仍然需要加锁。

(三)饿汉模式举例

在程序开始时就会产生一个类实例,并在以后返回该实例。

测试代码:

class Singleton
{
private:
Singleton(){}
static Singleton *m_instance;
public:
static Singleton *getInstance(void)
{
return m_instance;
}
}; Singleton* Singleton::m_instance = new Singleton();

C++学习之路(四):线程安全的单例模式的更多相关文章

  1. Redis——学习之路四(初识主从配置)

    首先我们配置一台master服务器,两台slave服务器.master服务器配置就是默认配置 端口为6379,添加就一个密码CeshiPassword,然后启动master服务器. 两台slave服务 ...

  2. zigbee学习之路(四):按键控制(中断方式)

    一.前言 通过上次的学习,我们学习了如何用按键控制led,但是在实际应用中,这种查询方式占用了cpu的时间,如果通过中断控制就可以解决这个问题,我们今天就来学习按键控制的中断方式. 二.原理分析 传统 ...

  3. [原创]java WEB学习笔记79:Hibernate学习之路--- 四种对象的状态,session核心方法:save()方法,persist()方法,get() 和 load() 方法,update()方法,saveOrUpdate() 方法,merge() 方法,delete() 方法,evict(),hibernate 调用存储过程,hibernate 与 触发器协同工作

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  4. Qt 学习之路:线程总结

    前面我们已经详细介绍过有关线程的一些值得注意的事项.现在我们开始对线程做一些总结. 有关线程,你可以做的是: 在QThread子类添加信号.这是绝对安全的,并且也是正确的(前面我们已经详细介绍过,发送 ...

  5. Qt 学习之路:线程和 QObject

    前面两个章节我们从事件循环和线程类库两个角度阐述有关线程的问题.本章我们将深入线程间得交互,探讨线程和QObject之间的关系.在某种程度上,这才是多线程编程真正需要注意的问题. 现在我们已经讨论过事 ...

  6. Qt 学习之路:线程和事件循环

    前面一章我们简单介绍了如何使用QThread实现线程.现在我们开始详细介绍如何“正确”编写多线程程序.我们这里的大部分内容来自于Qt的一篇Wiki文档,有兴趣的童鞋可以去看原文. 在介绍在以前,我们要 ...

  7. Qt 学习之路 :线程简介

    现代的程序中,使用线程的概率应该大于进程.特别是在多核时代,随着 CPU 主频的提升,受制于发热量的限制,CPU 散热问题已经进入瓶颈,另辟蹊径地提高程序运行效率就是使用线程,充分利用多核的优势.有关 ...

  8. python学习之路 四 :文件处理

    本节重点 掌握文件的读.写.修改方法 掌握文件的处理模式的区别 一.文件读取 ​    ​1.读取全部内容 # 一次性读取文件 f = open("test.txt",'r',en ...

  9. Java学习之路(四):面向对象

    Java中的面向对象 概念:面向对象的原本的意思是“”万物皆对象“” 面向对象思想的特点: 是一种更符合我们思想习惯的思想,将复杂的事情简单化 使我们角色发生了转换,将我们从执行者变成了指挥者 面向对 ...

  10. react.js学习之路四

    针对学习react.js中,我感觉最大的疑惑点就是bind(this)的绑定和指向问题了,我被这个问题弄的头昏,有时候调用组件的时候,直接显示undefined,不存在这个组件,当时的心情是崩溃的,整 ...

随机推荐

  1. [OS] 信号量(Semaphore)

    一个信号量S是一个整型量,除对其初始化外,它只能由两个原子操作P和V来访问.P和V的名称来源于荷兰文proberen(测试)和verhogen(增量),后面亦将P/V操作分别称作wait(), sig ...

  2. hdu 3367 Pseudoforest (最小生成树)

    Pseudoforest Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Tot ...

  3. [洛谷P4980]【模板】Polya定理

    题目大意:给一个$n$个点的环染色,有$n$中颜色,问有多少种涂色方案是的旋转后本质不同 题解:$burnside$引理:$ans=\dfrac1{|G|}\sum\limits_{g\in G}A_ ...

  4. bzoj3110: [Zjoi2013]K大数查询 【树套树,标记永久化】

    //========================== 蒟蒻Macaulish:http://www.cnblogs.com/Macaulish/  转载要声明! //=============== ...

  5. Android Service 生命周期

    Service概念及用途: Android中的服务,它与Activity不同,它是不能与用户交互的,不能自己启动的,运行在后台的程序,如果我们退出应用时,Service进程并没有结束,它仍然在后台运行 ...

  6. IDEA的使用总结篇-1

    随笔:随着回首所在的公司的日益扩大,所在的技术中心也日渐兵强马壮,但由于各位新老同仁的开发工具一直未曾统一,所以小编的老大终于一声令下,统一开发工具!统一使用IDEA,而且每个人今天要交一份IDEA的 ...

  7. django项目初探

    一:创建django项目 设置数据库(默认sqlit3) mysql: setting:中设置 DATABASES = { 'default': { 'ENGINE': 'django.db.back ...

  8. Java CPU占用率高分析

    首先,通过top命令找出CPU占用率高的进程: 然后,通过ps -o THREAD,tid,time -mp 2066命令找出执行时间最长的线程的TID 将有问题的TID转为16进制格式: print ...

  9. How far away ? LCA求树上两点距离

    How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  10. BroadcastReceiver学习

    一.使用系统广播.以监听电话状态为例 1.写一个类继承自BroadcastReceiver类 package com.diysoul.android.blacklist.receivers; impo ...