C++多线程环境下的单例类对象创建

本文介绍了在多线程环境下使用C++的不同方法创建单例对象,包括使用局部静态变量、无锁编程、std::unique_ptr和std::call_once或std::atomic_flag实现线程安全的单例。

使用C++无锁编程实现多线程下的单例模式

贺志国
2023.8.1

在多线程环境下创建一个类的单例对象,要比单线程环境下要复杂很多。下面介绍在多线程环境下实现单例模式的几种方法。

一、尺寸较小的类单例对象创建

如果待创建的单例类SingletonForMultithread内包含的成员变量较少,整个类占用的内存空间较小,则可使用局部静态变量来创建单例对象。C++ 11标准保证在多线程环境下,在第一个线程未完成静态对象的构建前,其他线程必须等待其完成,因此是线程安全的。如果类的尺寸较大,静态变量存储栈区无法容纳该类的单例对象,则禁止使用该方法。例如:64位Linux系统默认栈的最大空间为8 MB,64位Windows系统默认栈的最大空间为1 MB,当待创建的单例对象尺寸接近或超过上述栈的默认存储空间时,如使用该方法创建则会导致程序崩溃。示例代码如下所示:

class SmallSingletonForMultithread {
   
   
 public:
  static SmallSingletonForMultithread& GetInstance() {
   
   
    static SmallSingletonForMultithread instance;
    return instance;
  }
  
 private:
  SmallSingletonForMultithread() = default;
  ~SmallSingletonForMultithread() = default;

  SmallSingletonForMultithread(const SmallSingletonForMultithread&) = delete;
  SmallSingletonForMultithread& operator=(const SmallSingletonForMultithread&) = delete;
  SmallSingletonForMultithread(SmallSingletonForMultithread&&) = delete;
  SmallSingletonForMultithread& operator=(SmallSingletonForMultithread&&) = delete;
};

二、尺寸较大的类单例对象创建(使用无锁编程来实现)

在实际工作中,由于某些单例类的尺寸较大,静态变量存储栈区无法容纳该单例对象,因此无法使用上述方法来创建单例对象,这时需要使用new在堆区动态创建单例对象。为了避免多线程环境下对于单例对象的抢夺,可使用C++无锁编程来实现。在程序结束时使用atexit(DestoryInstance)来删除单例对象,示例代码如下所示:

#include <atomic>
#include <cassert>
#include <memory>
#include <thread>
#include <vector>

namespace {
   
   
constexpr size_t kThreadNum = 2000;
}

class SingletonForMultithread {
   
   
 public:
  static SingletonForMultithread* GetInstance() {
   
   
    if (!instance_.load(std::memory_order_acquire)) {
   
   
      auto* new_ptr = new SingletonForMultithread;
      SingletonForMultithread* old_ptr = nullptr;
      if (!instance_.compare_exchange_strong(old_ptr, new_ptr,
                                             std::memory_order_release,
                                             std::memory_order_relaxed)) {
   
   
        // If the CAS operation fails, another thread has created a singleton
        // object, and it's necessary to delete the temporary object created by
        // the current thread.
        delete new_ptr;
        new_ptr = nullptr;
      }
      
      // When the program exits, the function to delete the singleton object 
      // is called.
      atexit(DestoryInstance);
    }

    return instance_.load(std::memory_order_relaxed);
  }

  static void DestoryInstance() {
   
   
    if (instance_.load(std::memory_order_acquire)) {
   
   
      auto* old_ptr = instance_.load(std::memory_order_relaxed);
      SingletonForMultithread
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值