了解单例模式

单例模式的实现方法很多。要考虑:线程安全,生命周期,资源释放等问题会涉及到整个编程体系。

单例模式singleton

普通的简单的单例模式实现:

class Singleton
{
public:
    static Singleton& instance()
    {
        if(m_pinstance== 0)
        { 
           //很巧两个线程同时进入该区域,就会创建2次堆对象,
           //并且第一次new的堆对象再也控制不住了,要对_instance变量加上互斥锁:
            m_pinstance= new Singleton();
        }
        return *m_pinstance;
    }
private:
    Singleton(){};
    ~Singleton(){};
    Singleton(const Singleton&){};
    Singleton& operator=(const Singleton&){};

private:
    static Singleton* m_pinstance;

};

Singleton* Singleton::m_pinstance= 0;

上面的单例模式直到Instance()首次被调用,才会生成唯一实例,这是被称为延迟初始化(Lazy initialization)的设计逻辑,避免程序在初始化时加载过重,在启动初始化消耗较大的程序里,这种设计思想有很大优势。

懒加载模式Lazy Singleton不是线程安全的单例模式。

注意,Instance()的返回值是实例的引用而不是指针,为的是保险防止使用者delete唯一实例。

线程安全的单例模式

简单的加上一个锁,解决了线程安全问题,但是引起效率低。加锁是比较慢的。

Singleton* Singleton::instance() {
    Lock lock;    //每次使用都加锁判断,锁的频繁,资源浪费,性能低
    if (_instance == 0) {
        _instance = new Singleton;
    }
    return _instance;

只有第一次调用该函数,在堆内存创建实例时才需要加锁 。

双检查锁

用双检测锁模式(Double-Checked Locking Pattern)解决线程安全问题。在java社区内相关文章很多。

Singleton* Singleton::instance() {
    if (_instance == 0) { // 1st check //解决频繁上锁,有实例后不再加锁
        Lock lock;
        if (_instance == 0) { // 2nd check
            _instance = new Singleton;   //这句有三个步骤,仍然有可能多个线程进来
        }
    }
    return _instance;
}

由于编译器的优化、处理器的优化,可能会导致指令重排,指令顺序优化排列。执行结果不变。

_instance  = new singleton() 这句代码有三个步骤:

1.按对象大小在堆中开辟分配空间    operator new(sizeof(Singleton)); // Step 1
2.在分配的空间中构造对象初始化   new (_instance) Singleton; // Step 2
3.使_instance指向分配的内存地址     _instance =  内存对象   // Step 3  

编译器的执行顺序可能是123 或者132 ,就会造成多个线程同时进入临界区执行其中,多new一个对象

使用volatile关键字的代码,也不能保证正常工作在多线程环境中。

双检查锁缺点:如指令重排、多核处理器等问题,让双检查锁实现起来比较复杂。

饿汉模式 Eager Singleton

在程序开始的时就完成了实例的创建。静态属性instance在main函数之前初始化,所以没有线程安全的问题。

潜在问题:在于no-local static对象(函数外的static对象)在不同编译单元(可理解为cpp文件和其包含的头文件)中的初始化顺序是未定义的。如果在初始化完成之前,调用 Instance()方法,会返回一个未定义的实例。

class Singleton  
{
    public:
        static Singleton& Instance()
        {
            return instance;
        }
    private:
        Singleton();
        ~Singleton();
        Singleton(const Singleton&);
        Singleton& operator=(const Singleton&);
    private:
        static Singleton instance;
}
Singleton Singleton::instance;  

局部静态变量 Singleton

 c++11标准做法:使用local static对象作为唯一实例。当第一次调用Instance()时才创建实例。

class Singleton  
{
    public:
        static Singleton& Instance()
        {
          static Singleton instance;
          return instance;
        }
    private:
        Singleton();
        ~Singleton();
        Singleton(const Singleton&);
        Singleton& operator=(const Singleton&);
};


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值