设计模式 单例模式再探

        总结单例类在实际应用中存在的问题与解决办法

单例多线程中存在的问题

        经过前面的学习,已知单例会在成员函数中判断 Instancce是否为nullptr,但是但在多线程中由于操作系统时间片的调度问题,可能会在线程1中判断完 if(Instance == nullptr),并确定该判断语句成立之后,切换到线程2,线程2也会执行 if(Instance == nullptr)语句,并且可能会执行Instance = new obj(),之后再切换回线程1继续执行后续语句,那么就会导致线程1,线程2都创建了obj类的对象。

双重锁

        一般会想到在创建单例中加锁,但是如果每一次调用函数时都经历加锁和解锁的过程,就会严重影响程序执行的效率,那么将其进行优化。

        lock_guard简化了 lock/unlock 的写法, lock_guard在构造时自动锁定互斥量, 而在退出作用域时会析构自动解锁。

        注意重点 m_instance!=nullptr,那么m_instance一定被new了,但是if(m_instance==nullptr)成立,不一定m_instance没被new过,因为上文所说的操作系统时间片的调度问题。使用两层 if()判断语句,在二者之间加锁,那就确保只会在一个线程中进行new,因为第一个if判断不能肯定是否被new过,但是成功锁住之后再次判断,未被满足if判断就会new一个,不满足那就是被new过了。

static mutex mtx;    //锁
    
static obj* get_Instance()
{
        if(m_instance == nullptr)
        {
            lock_guard<mutex> lock(mtx);
            if(m_instance == nullptr)
            {
                m_instance = new obj();
            }
        }
        return m_instance;
    }

        同时还要注意“内存访问重新排序”所导致的双重锁失效的问题,因此该方法并不太推荐。

饿汉式

        就如名字一样,饿汉式很“饿”,因此在给Instance赋初值的时候不再赋值为nullptr,而是直接new obj类对象。

class obj
{
private:
    obj(){}
public:
    static obj* get_Instance()
    {
        return m_instance;
    }

private:
    static obj* m_instance;     //指向本类对象的指针
};

//直接定义赋值
obj* obj::m_instance = new obj();

        用 new 创建的 obj对象的代码会早于 main() 主函数执行,所以在main()中obj::m_instance已经有了有效值,后续对get_Instance调用就不需要加锁。

懒汉式

        不同于饿汉式一开始就创建,懒汉式就是在需要的时候再进行创建。程序执行之后该单例对象并不存在,只有第一次调用get_Instance成员函数该单例类对象才会创建,这种方式可以更好的控制单例的创建时机,以免过早加载,如果obj类非常庞大的话很容易造成资源消耗。

class obj
{
private:
    obj(){}
public:
    static obj* get_Instance()
    {
        if(m_instance == nullptr)
        {
            m_instance = new obj();
        }
        return m_instance;
    }

private:
    static obj* m_instance;     //指向本类对象的指针
};

//主函数中使用
 obj* p1 = boj::get_Instance();  //或者直接使用boj::get_Instance()

        一个好的解决多线程创建obj类单例对象的方法就是在main()主函数中,在创建任何其他线程之前先执行一次“boj::get_Instance();”将单例对象单独创建出来,这样后续调用getInstance函数的时候,就只读取到m_instance成员变量,那么也就不需要加锁了。

学习资料:《C++新经典设计模式》 王建伟编著

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值