C++ 03 单例模式

  1. 说明

    • 创建方式

      • 有很多种,但是需要从效率,内存,线程安全等方面考虑.
    • 内容

      • 从不同的方向进行优化.
      • 适应不同的场景。
      • 从简单到复杂。
  2. 分析

    • 单例模式核心

      • 只有一个对象.
    • 实现核心

      • 构造函数私有化.
      • 通过静态函数对外提供获取实例.
  3. 饿汉式

    • 优点

      • 实现简单。
      • 线程安全,程序启动时创建。
    • 缺点

      • 如果类没有被使用,且类特别大,那么就会浪费内存。
    • 案例

      class Single {
      public:
         static Single* getInstance(){return instance;}
      private:
         static Single* instance;
         Single(){
             // some initial
         }
      };
      Single* Single::instance = new Single();
      
      int main(){
         Single::getInstance();
      }
      
      
  4. 懒汉式

    • 说明

      • 优化一些, 真正调用时才创建。
    • 优点

      • 真正需要的时候才调用创建.
    • 缺点

      • 多线程不安全。
      • 多个线程执行到nullptr == instance的时候,可能都满足,就都创建类并赋值.
      • 那么问题就是,单例不再真正的单例,而且还没办法释放.
    • 案例

      class Single {
      private:
         static Single* instance;
         Single(){
             // some initial
         }
      public:
         static Single* getInstance(){
             if(nullptr == instance) {
                 instance = new Single();
             }
             return instance;
         }
      };
      Single* Single::instance = nullptr;
      
      int main(){
         Single::getInstance();
      }
      
      
  5. 线程安全

    • 说明

      • 懒汉式线程安全.
    • 优点

      • 实现简单.
    • 缺点

      • 并发不高.
    • 案例

      #include <mutex>
      class Single {
      private:
         static Single* instance;
         Single(){
             // some initial
         }
      public:
         static Single* getInstance(){
             std::mutex instance_mutex;
             instance_mutex.lock();
             if(nullptr == instance) {
                 instance = new Single();
             }
             instance_mutex.unlock();
             return instance;
         }
      };
      Single* Single::instance = nullptr;
      
      int main(){
         Single::getInstance();
      }
      
      
      • 因为每次访问都会互斥,可能导致其他睡眠.
  6. 线程安全错误优化

    • 说明

      • 创建的地方加锁
    • 案例

      #include <mutex>
      class Single {
      private:
         static Single* instance;
         Single(){
             // some initial
         }
      public:
         static Single* getInstance(){
             if(nullptr == instance) {
                 std::mutex instance_mutex;
                 instance_mutex.lock();
                 instance = new Single();
                 instance_mutex.unlock();
             }
             return instance;
         }
      };
      Single* Single::instance = nullptr;
      
      int main(){
         Single::getInstance();
      }
      
      
      • 判断后再互斥创建,其实和懒汉式一样的.解锁了之后还是会继续执行并创建.
  7. 双重验证

    • 说明

      • 枷锁了之后再加判断.
    • 好处

      • 安全,效率高,且符合要求
    • 案例

      #include <mutex>
      class Single {
      private:
         static Single* instance;
         Single(){
             // some initial
         }
      public:
         static Single* getInstance(){
             if(nullptr == instance) {
                 std::mutex instance_mutex;
                 instance_mutex.lock();
                 if(nullptr == instance) {
                     instance = new Single();
                 }
                 instance_mutex.unlock();
             }
             return instance;
         }
      };
      Single* Single::instance = nullptr;
      
      int main(){
         Single::getInstance();
      }
      
      
  8. 可选

    • 双重验证问题

      • lock之后,虽然大概率会成功,但是可以添加volatile保证编译优化不被优化。
      • 内存屏障强制的写和读即可.
      • 还是需要加锁,可靠性也更高。
    • 可优化

      • 通过volatile,内存屏障和循环的方式避免加锁.
  9. 总结

    • 单例属于简单的用例,属于创造型的涉及模式,主要应对创建的场景.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值