std string与线程安全_C++线程安全的单例模式实现

a265414d354015c1606ab4f12be33beb.png

对于某些类来说,我们希望这些类只被实例化一次,比如连接池、类工厂、文件系统等。这就是设计模式中的单例模式(Singleton Pattern)。

在多线程并发环境中,如何线程安全的获取(初始化)实例?本文对目前学到的几种方法进行总结。

Meyers Singleton

Meyers Singleton的实现方式基于"static variables with block scope"的自动线程安全特性,非常简单易懂。

class MeyersSingleton{
public:
  static MySingleton& getInstance(){
    static MySingleton instance;
    // volatile int dummy{};
    return instance;
  }
private:
  MySingleton()= default;
  ~MySingleton()= default;
  MySingleton(const MySingleton&)= delete;
  MySingleton& operator=(const MySingleton&)= delete;
};

std::call_once & std::once_flag

这种方式基于C++新特性,保证多线程下实例化方法只被调用一次。

class CallOnceSingleton{
public:
  static MySingleton& getInstance(){
    std::call_once(initInstanceFlag, &MySingleton::initSingleton);
    // volatile int dummy{};
    return *instance;
  }
private:
  MySingleton()= default;
  ~MySingleton()= default;
  MySingleton(const MySingleton&)= delete;
  MySingleton& operator=(const MySingleton&)= delete;
  static MySingleton* instance;
  static std::once_flag initInstanceFlag;
  static void initSingleton(){
    instance= new MySingleton;
  }
};

MySingleton* MySingleton::instance= nullptr;
std::once_flag MySingleton::initInstanceFlag;

锁机制

std::mutex myMutex;

class MySingleton{
public:
  static MySingleton& getInstance(){
    std::lock_guard<std::mutex> myLock(myMutex);
    if ( !instance ){
        instance= new MySingleton();
    }
    // volatile int dummy{};
    return *instance;
  }
private:
  MySingleton()= default;
  ~MySingleton()= default;
  MySingleton(const MySingleton&)= delete;
  MySingleton& operator=(const MySingleton&)= delete;

  static MySingleton* instance;
};


MySingleton* MySingleton::instance= nullptr;

每次getInstance方法调用,都需要申请和释放锁,开销非常大。

原子变量atomic variables

实际上只有当程序启动,多个线程并发初始化第一个instance时,锁的同步才有必要。当第一个instance初始化之后,每次getInstance只需要读取已经创建好的instance即可,不需要使用互斥锁。

原子变量方法首先判断是否已经初始化实例,如果已经实例化,直接返回即可;否则回退至锁方案。对于原子变量的使用,可细分为Sequential Consistency和Acquire/Release两种方式。

Sequential Consistency

class MySingleton{
public:
  static MySingleton* getInstance(){
    MySingleton* sin= instance.load();
    if ( !sin ){
      std::lock_guard<std::mutex> myLock(myMutex);
      sin= instance.load();
      if( !sin ){
        sin= new MySingleton();
        instance.store(sin);
      }
    }   
    // volatile int dummy{};
    return sin;
  }
private:
  MySingleton()= default;
  ~MySingleton()= default;
  MySingleton(const MySingleton&)= delete;
  MySingleton& operator=(const MySingleton&)= delete;

  static std::atomic<MySingleton*> instance;
  static std::mutex myMutex;
};


std::atomic<MySingleton*> MySingleton::instance;
std::mutex MySingleton::myMutex;

Acquire/Release Semantic

class MySingleton{
public:
  static MySingleton* getInstance(){
    MySingleton* sin= instance.load(std::memory_order_acquire);
    if ( !sin ){
      std::lock_guard<std::mutex> myLock(myMutex);
      sin= instance.load(std::memory_order_relaxed);
      if( !sin ){
        sin= new MySingleton();
        instance.store(sin, std::memory_order_release);
      }
    }   
    // volatile int dummy{};
    return sin;
  }
private:
  MySingleton()= default;
  ~MySingleton()= default;
  MySingleton(const MySingleton&)= delete;
  MySingleton& operator=(const MySingleton&)= delete;

  static std::atomic<MySingleton*> instance;
  static std::mutex myMutex;
};
std::atomic<MySingleton*> MySingleton::instance;
std::mutex MySingleton::myMutex;

Singleton based on CRTP

以上的单例方法对于每个单例类目标,都要实现一次,难免有造轮子的感觉。这里介绍一种基于CRTP的单例实现:目标类通过继承模板类Singleton来实现单例。

template <typename Derived>
class Singleton {
 public:
  static Derived* GetInstance() {
    Derived* temp = instance_.load(std::memory_order_acquire);
    if (temp == nullptr) {
      std::lock_guard<std::mutex> lock(mutex_);
      temp = instance_.load(std::memory_order_relaxed);
      if (temp == nullptr) {
        temp = new Derived;
        instance_.store(temp, std::memory_order_release);
      }
    }
    return temp;
  }

 protected:
  Singleton() = default;
  ~Singleton() = default;
  Singleton(const Singleton&) = delete;
  Singleton& operator=(const Singleton&) = delete;

 private:
  static std::atomic<Derived*> instance_;
  static std::mutex mutex_;
};
template<typename Derived>
std::atomic<Derived*> Singleton<Derived>::instance_(nullptr);
template<typename Derived>
std::mutex Singleton<Derived>::mutex_;

引用

thread-safe initialization of a singleton​www.modernescpp.com The Curiously Recurring Template Pattern (CRTP) - Fluent C++​www.fluentcpp.com
4e68f4b92b4f0727a4714d54ef6a97ba.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值