线程安全的单例模式(C++)

172 阅读1分钟
#include <mutex>
/*懒汉式线程安全的单例模式*/
namespace Singleton1
{
  class Singleton1
  {

  public:
    ~Singleton1(){};

    // 获取单例对象
    static Singleton1 *GetInstance()
    {
      /*这里使用了两个if判断语句的技术称为double check local。只有指针为空的时候才加锁,
        避免每次调用 GetInstance的方法都加锁*/
      if (instance == NULL)
      {
        std::unique_lock<std::mutex> lock(m_Mutex); // 加锁
        if (instance == NULL)
        {
          instance = new Singleton1();
        }
      }

      return instance;
    };

  private:
    //唯一单例对象指针
    static Singleton1 *instance;
    //互斥锁,确保单例模式线程安全
    static std::mutex m_Mutex;
    //将构造函数设置位私有的
    Singleton1(){};
  };
  //初始化静态成员变量
  Singleton1 *Singleton1::instance = nullptr;
} // namespace Singleton1
/*
  局部静态变量的懒汉式线程安全的单例模式
  在c++11局部静态变量的方式里是线程安全的
*/
namespace Singleton2
{
  class Singleton2
  {
  public:
    // 获取单实例对象
    static Singleton2 &GetInstance();

  private:
    // 禁止外部构造
    Singleton2();
    // 禁止外部析构
    ~Singleton2();
  };

  Singleton2 &Singleton2::GetInstance()
  {
    // 局部静态特性的方式实现单实例
    static Singleton2 signal;
    return signal;
  }
} // namespace Singleton2
/*饿汉式单例 (本身就线程安全,即程序一运行就创建实例)*/
namespace Singleton3
{
  class Singleton3
  {
  public:
    // 获取单实例
    static Singleton3 *GetInstance()
    {
      return g_pSingleton;
    };
    // 释放单实例,进程退出时调用
    static void deleteInstance();

  private:
    // 将其构造和析构成为私有的, 禁止外部构造和析构
    Singleton3(){};
    ~Singleton3(){};
    // 唯一单实例对象指针
    static Singleton3 *g_pSingleton;
  };

  // 代码一运行就初始化创建实例 ,本身就线程安全
  Singleton3 *Singleton3::g_pSingleton = new Singleton3;
} // namespace Singleton3

/*
  总结:
    懒汉式是以时间换空间,适用于访问量较小时,推荐使用内部静态变量的懒汉单例,代码量少
    饿汉式是以空间换时间,适用于访问量较大时,或者线程比较多的的情况
*/