C++11多线程编程 7.单例设计模式共享数据分析、解决,call_once

本文深入探讨C++中的单例设计模式,重点讲解如何确保在多线程环境下单例对象的唯一性和线程安全性。通过使用std::call_once和std::once_flag,避免了多次实例化和锁的过度使用,提高了程序效率。
摘要由CSDN通过智能技术生成

#include<iostream>
#include<string>
#include<vector>
#include<mutex>
#include<thread>
using namespace std;
std::mutex resourece_mutex;
std::once_flag g_flag;//这是一个系统定义的标记
class mycas //这是一个单例类
{
    static void CreateInstance() {//只被调用一次的函数
        m_instance = new mycas();
        static CGarhuishou cj;
    }
private:
    mycas() {}//私有化了构造函数
private:
    static mycas* m_instance;
public:
    static mycas* Getinstance()
    {
        提高效率
        a)if(m_instance != nullptr)如果这个成立,则表示m_instance已经被new过了;
        b)如果if(m_instance == nullptr)不代表m_instance一定没被new过
        //if (m_instance == nullptr) {//双重锁定(双重检查)
        //    std::unique_lock<std::mutex> mymutex(resourece_mutex);//自动加锁
        //    if (m_instance == nullptr) {
        //        m_instance = new mycas();
        //        static CGarhuishou cj;
        //    }
        //}  //因为要写到call_once()所以将这一块代码注释掉

        std::call_once(g_flag, CreateInstance);//两个线程同时执行到这里,其中一个线程要等另外一个线程执行完毕CreateInstance
                                            //这里可以吧这个g_flag看成一个锁。
        return m_instance;

    }

    class CGarhuishou {//类中套类,用来释放对象 
    public:
        ~CGarhuishou() {
            if (mycas::m_instance) {
                delete mycas::m_instance;
                mycas::m_instance = nullptr;
            }
        }
    };

    void function() {
        cout << "测试" << endl;
    }
};
//类静态变量初始化
mycas* mycas::m_instance = nullptr;

//线程入口函数
void mythread() {
    cout << "线程开始执行了" << endl;
    mycas* pa = mycas::Getinstance();//这里可能有问题
    cout << "线程执行完毕了" << endl;
}
int main()
{
    /*    (1)设计模式大概谈
    *        “设计模式”:代码的一些写法,(这些写法跟常规写法不太一样):程序灵活,维护起来可能方便,但是别人接管,阅读代码很痛苦
    *        用设计模式写出来的代码是很晦涩的;《head first》
    *        老外为了应付很大的项目时候,吧项目的开发经验、模块划分经验,总结整理成设计模式。(先有开发需求,后有理论总结和整理);
            设计模式拿到中国来,不太一样,拿着一个程序(项目)往设计模式上套;一个小小的项目,它非要弄几个设计模式进去,本末倒置
            设计模式肯定有它独特的优点,活学活用,不要生搬硬套;
    *    (2)单例设计模式
    *        单例设计模式,使用的频率高,
    *        单例:整个项目中,有某个或者某些特殊的类,属于该类的对象,我只能创建一个,多了我创建不了,
    *        单例类;
    *        注意:不能再析构函数中释放自身对象
    *            因为析构一个对象,是需要调用这个对象的析构函数,如果在析构函数里面delete自身对象,那么delete中又要调用析构函数,陷入析构循环。
    *    (3)单例设计模式共享数据问题分析,解决
    *        最好在主线程创建这个单例类,在其他线程创建之前就创建这个单例类,并且完成初始化,把该装载的数据装载,数据为只读
    *        实际中面临的问题:    需要在我们自己创建的线程而不是主线程中来创建这个mycas这个单例类的对象,这种线程还不止一个
    *        我们可能要面临Getinstance()这种成员函数要互斥;
    *        问题1:可能第一个线程在执行m_instance = new mycas();的时候,第二个线程判断m_instance == nullptr,也会去new这个对象,这样就会出现问题
    *        解决办法:加锁
    *        问题2:在if上面直接加锁,只是为了第一次new这个对象而加个锁,这样在每次使用这个函数的时候都会进行加锁,效率大大降低
    *        解决办法:双重检查。提高效率。只有在线程才开始的时候,多个线程进行判断,加锁,一旦一个加锁成功,创建对象成功,其他线程就直接返回就OK了,
    *                下次再进行创建对象时候,也不用加锁,直接返回该对象就好了
    *    (3)std::call_once() C++引入的函数,该函数的第二个参数是一个函数名a();
    *        功能:能够保证函数a只被调用一次。即便有许多线程,每个线程都调用了这个函数,只要用了这个函数,编译器就会保证这个函数a只被调用一次。
    *             具备互斥量的能力,效率上,比互斥量消耗的资源更少;
    *            call_once()需要和一个标记结合使用,这个标记是std::once_flag;其实once_flag是一个结构
    *            call_once()通过这个标记来决定对应的函数()是否执行,调用call_once()成功后,call_once()就把这个标记设置为已调用状态
    *                后续再次调用call_once()时候,只要这个标记为已调用状态,那么对应的函数a就不会再被执行。
    * 
            
    */
    /*mycas m;
    mycas m2;*///构造函数私有化了,不能通过这个方式生成类对象。
    mycas* p_a = mycas::Getinstance();//创建一个对象,返回该类(mycas)对象的指针;
    p_a->function();

    //如下两个线程是同一个入口函数,但是要记住,这是两个线程,所以这里会有两个流程,或者两条通路同时执行mythread这个函数。同时执行getrinstance就可能出问题
        
    std::thread mytobj1(mythread);
    std::thread mytobj2(mythread);
    const int aaa=10;
    mytobj1.join();
    mytobj2.join();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值