C++11多线程---单例设计模式

本文介绍了设计模式的概念及其在软件开发中的重要性,特别是单例模式作为创建型模式的一种,详细阐述了C++11中实现单例模式的方法,包括传统的双重检查锁定和使用`std::call_once`来确保线程安全。同时,讨论了在多线程环境下如何解决单例模式中的共享数据问题,展示了如何利用互斥锁和`std::call_once`来保证资源的正确初始化和避免竞态条件。
摘要由CSDN通过智能技术生成

一、设计模式简介

设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。

设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理地运用设计模式可以完美地解决很多问题,每种模式在现实中都有相应的原理来与之对应,每种模式都描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是设计模式能被广泛应用的原因。

设计模式是应对大项目时的一种开发经验,模块划分经验,更是一种经验的总结。实现有开发需求,然后出现的一种理论。它更是一种工具,那么对于工具的使用是灵活的,使用设计模式不要生搬硬套,在真正需要的时候再去使用设计模式。

二、单例设计模式C++实现

单例模式(Singleton Pattern)是最简单的设计模式之一,使用的频率比较高。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象

注意:

  • 1、单例类只能有一个实例。
  • 2、单例类必须自己创建自己的唯一实例。
  • 3、单例类必须给所有其他对象提供这一实例。

C++11单例模式实现:

//
// Created by yangjq on 22-7-8.
//
#include <iostream>
#include <thread>
#include <vector>
#include <list>
#include <mutex>

using namespace std;

class MyCAS{
private:
    MyCAS(){}//私有化了构造函数
private:
    static  MyCAS *m_instance;//静态成员变量
public:
    static  MyCAS *GetInstance(){
        if(m_instance == nullptr){
            m_instance = new MyCAS();
            static CGarRec cl;
        }
        return m_instance;
    }
    //类中套类,用来回收对象
    class CGarRec{
    public:
        ~CGarRec(){
            if(MyCAS::m_instance){
                delete MyCAS::m_instance;
                MyCAS::m_instance = nullptr;
            }
        }
    };

    void func(){
        cout << "测试" << endl;
    }
};

MyCAS *MyCAS::m_instance = nullptr;

int main(){
//    MyCAS a;
//    MyCAS a2;
    MyCAS *p_a = MyCAS::GetInstance();//创建一个对象,返回该类对象的指针.
//    MyCAS *p_b = MyCAS::GetInstance();//就算再执行一次,返回的指针还是第一次创建的对象指针
    p_a->func();//打印一次测试
    MyCAS::GetInstance()->func();//再打印一次测试

    return 0;
}

上面代码有一个私有化构造函数的东西,一般来说,构造函数都是放在公有区,要是把构造函数放在私有区在外部都构造不了对象了。在一种特殊情况下,会把构造函数放在私有区,不允许被外界创建对象,我们只需要一个对象即可。

还有一个类中嵌套类,主要目的是实现回收对象,既然能够创建对象,那么就需要一个删除对象的东西。在整个程序退出的时候,必然会执行嵌套类的析构函数,如果m_instance被new过,那就会被析构函数delete。

三、单例设计模式共享数据问题分析、解决

//
// Created by yangjq on 22-7-8.
//
#include <iostream>
#include <thread>
#include <vector>
#include <list>
#include <mutex>

using namespace std;

std::mutex resource_mutex;

class MyCAS{
private:
    MyCAS(){}//私有化了构造函数
private:
    static  MyCAS *m_instance;//静态成员变量
public:
    static  MyCAS *GetInstance(){
        if(m_instance == nullptr){//双重锁定或双重检查
            std::unique_lock<std::mutex> mymutex(resource_mutex);
            if(m_instance == nullptr){
                m_instance = new MyCAS();
                static CGarRec cl;
            }
        }
        return m_instance;
    }
    //类中套类,用来回收对象
    class CGarRec{
    public:
        ~CGarRec(){
            if(MyCAS::m_instance){
                delete MyCAS::m_instance;
                MyCAS::m_instance = nullptr;
            }
        }
    };

    void func(){
        cout << "测试" << endl;
    }
};

MyCAS *MyCAS::m_instance = nullptr;
//线程入口函数
void mythread(){
    cout << "我的线程开始执行了!" << endl;
    MyCAS *p_a = MyCAS::GetInstance();//如果不加互斥量,这里会有问题,两个线程可能会同时执行此代码
    p_a->func();
    cout << "我的线程结束执行了!" << endl;
}

int main(){
    //两个线程同时执行mythread,
    std::thread mytobj1(mythread);
    std::thread mytobj2(mythread);
    mytobj1.join();
    mytobj2.join();

    return 0;
}

主要看双重锁定部分,很巧的应用。

四、std::call_once

std::call_once是c++11引入的函数,该函数的第二参数是一个函数名;其功能是能够保证函数只被调用一次;其具备互斥量的能力,而且效率上比互斥量消耗的资源更少;其需要与标记once_flag结合使用,once_flag是一个结构;其通过once_flag标记判断函数是否执行,调用call_once成功后,call_once会把once_flag标记设置为一种已调用状态。

//
// Created by yangjq on 22-7-8.
//
#include <iostream>
#include <thread>
#include <vector>
#include <list>
#include <mutex>

using namespace std;

std::mutex resource_mutex;
std::once_flag g_flag;//这是个系统定义的标记

class MyCAS{
    static void CreateInstance(){//只被调用一次的
        m_instance = new MyCAS();
        cout << "CreateInstance执行了 !" << endl;
        static CGarRec cl;
    }
private:
    MyCAS(){}//私有化了构造函数
private:
    static  MyCAS *m_instance;//静态成员变量
public:
    static  MyCAS *GetInstance(){
        std::call_once(g_flag,CreateInstance);//执行到这,其中一个线程要等。
        cout << "call_once执行完毕 !" << endl;
        return m_instance;
    }
    //类中套类,用来回收对象
    class CGarRec{
    public:
        ~CGarRec(){
            if(MyCAS::m_instance){
                delete MyCAS::m_instance;
                MyCAS::m_instance = nullptr;
            }
        }
    };

    void func(){
        cout << "测试" << endl;
    }
};

MyCAS *MyCAS::m_instance = nullptr;
//线程入口函数
void mythread(){
    cout << "我的线程开始执行了!" << endl;
    MyCAS *p_a = MyCAS::GetInstance();//如果不加互斥量,这里会有问题,两个线程可能会同时执行此代码
    p_a->func();
    cout << "我的线程结束执行了!" << endl;
}

int main(){
    //两个线程同时执行mythread,
    std::thread mytobj1(mythread);
    std::thread mytobj2(mythread);
    mytobj1.join();
    mytobj2.join();

    return 0;
}

参考:c++11并发与多线程视频课程_哔哩哔哩_bilibili

设计模式简介 | 菜鸟教程

单例模式 | 菜鸟教程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿巴乾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值