线程安全的单例模式

单例模式:是非常典型常用的一种设计模式(大佬们针对典型场景设计的解决方案)

单例模式的特点
某些类,只应该具有一个对象(实例),就称之为单例。
例如一个男人只能有一个媳妇。
在很多服务器开发场景中,经常需要让服务器加载很多的数据(上百G)到内存中,此时往往要用一个单例的类来管理这些数据。

饿汉方式和懒汉方式

  1. 吃完饭立刻洗碗,这就是饿汉方式。因为下一顿吃的时候可以立刻拿着碗就能吃饭;
  2. 吃完饭,先把碗放下,然后下一顿饭用到这个碗了再洗碗,这就是懒汉方式

饿汉方式的实现
    使用static就可以—将一个成员变量设置为静态变量,则所有对象共用一份资源,并且在程序初始化时就会申请资源(不涉及线程安全)。

代码实现:

template <typename T>
class Singleton{
	static T data;
public:
	static T* GetInstance(){
		return &data;
	}
};

只要通过 Singleton这个包装类来使用T对象,则一个进程中只有一个T对象的实例。

懒汉方式的实现
    资源在使用的时候发现还没有加载,则申请加载。程序初始化比较快,第一次运行某个模块的时候就会比较慢,因为这时候去加载相应资源。

代码实现:

#include <cstdio>
#include <mutex>
#include <thread>

std::mutex g_mutex;

class single_instance{
public:
    volatile static int *get_instance(){
        // 不管—data资源是否已经被加载, 每次都要加锁判断, 然后解锁
        // 若资源已经加载过了, 加锁解锁就有点浪费资源, 并且容易造成锁冲突
        // 4. 二次判断, 避免每次都会加锁解锁
        if(_data == NULL){
            //-----------------//
            g_mutex.lock();// 3.实现线程安全
            if(_data == NULL){
                _data = new int;
                *_data = 10;
            }
            g_mutex.unlock();
        }
        return _data;
    }

private:
    //1.static 保证所有对象使用同一份资源
    //2.volatile 防止编译器过度优化
    volatile static int *_data;
};
volatile int *single_instance::_data = NULL;

实现所注意的细节

  1. 使用static保证所有对象使用同一份资源;
  2. 使用volatile,防止编译器过度优化
  3. 实现线程安全,保证资源判断以及申请过程是安全的
  4. 外部二次判断,以及避免资源已经加载成功每次获取都要加锁解锁,以及所带来的锁冲突。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值