并发和多线程(六) 单例设计模式共享数据分析、解决,call_once

我的实践:

#include <iostream>
#include <thread>
#include <list>
#include <mutex>

using namespace std;
mutex my_mutex;
once_flag g_flag;

//1.只有new但是没有回收内存
class MyCAS//这是一个单例类
{
    static void CreatInstance()
    {
        chrono::milliseconds time(10000);
        this_thread::sleep_for(time);
        cout<<"CreatInstance执行了一次"<<endl;
        m_instance = new MyCAS();
         static Garbage cl;
    }
    
private:
    MYCAS(){}//私有化了构造函数
    

private:
    static MyCAS *m_instance;//声明

public:
/*
    //2.类中套类,解决释放问题,但是回顾GetInstance()函数,还是存在多线程中互斥的问题。
    static MyCAS *GetInstance(){
        if(m_instance == NULL){
            m_instance = new MyCAS();
            static Garbage cl;//在程序退出是调用析构函数,析构函数里面释放m_instance
        }
        return m_instance;
    }
*/
    //3.加锁,但是低效,只要调用GetInstance()函数,就会进入锁
    /* static MyCAS *GetInstance(){
        unique_lock<mutex> Umutex(my_mutex);//自动加锁
        if(m_instance == NULL){
            m_instance = new MyCAS();
            static Garbage cl;
        }
        return m_instance;
    } */
    //4.对3的改进,高效,叫双重锁定(双重检查)
    /* static MyCAS *GetInstance(){
        if(m_instance == NULL)
        {
            unique_lock<mutex> Umutex(my_mutex);//自动加锁
            if(m_instance == NULL){
                m_instance = new MyCAS();
                static Garbage cl;
            }
        }
        return m_instance;
    }  */
    //5.用call_once
    static MyCAS *GetInstance(){
        std::call_once(g_flag, CreatInstance);
        cout<<"call_once执行完毕"<<endl;
        return m_instance;
    } 
    
    class Garbage//用于回收m_instance;
    { 
    public:
        ~Garbage()
        {
            if(MyCAS::m_instance)
            {
                delete MyCAS::m_instance;
                m_instance = NULL;
            }
        }
    };

    void func(){
        cout << "this is a test" << endl;
    }

};



//类静态成员变量初始化,类内只是声明,还需要定义。
MyCAS *MyCAS::m_instance = NULL; 

//线程入口函数
void mythread()
{
    cout<<"我的线程开始执行了"<<endl;
    MyCAS *p_a = MyCAS::GetInstance();
    p_a->func();
    cout<<"我的线程执行完毕了"<<endl;
    return;
}

int main(){
    //1.设计模式 大概谈 
    // 《Head first》
    // 应对特别大的项目的时候,把项目的开发经验、模块划分经验,总结整理成 设计模式。
    //避免小程序往设计模式上套。违背了初衷。设计模式有它的优点,要活学活用。

    //2.单例设计模式
        //某些项目中,只能创建该类的一个对象。
    /* MyCAS *p_a = MyCAS::GetInstance();
    p_a->func();
    getchar(); */

    //3.单例模式共享数据问题的分析
        //面临GetInstance()函数互斥的问题,比如第一个线程判断m_instance为空之后,还没有new。第二个线程也判断为空。
    thread my_thread1(mythread);
    thread my_thread2(mythread);
    getchar();
    // 4.call_once
        // c++11引入的函数,加入在多线程中,函数的某一个参数是函数名a(),
        // call_once可以保证a()函数只调用一次
        // call_once具备互斥量这种能力,比互斥量消耗的资源少,效率高
        // 需要和一个标记使用,这个标记std::once_flag;其实once_flag是一个结构
        // 如果a()执行了,call_flag就会被设置为已调用状态。
    

}

 

1.设计模式

  • 程序灵活,维护起来可能方便,用设计模式理念写出来的代码很晦涩,但是别人接管、阅读代码都会很痛苦
  • 老外应付特别大的项目时,把项目的开发经验、模块划分经验,总结整理成设计模式
  • 中国零几年设计模式刚开始火时,总喜欢拿一个设计模式往上套,导致一个小小的项目总要加几个设计模式,本末倒置
  • 设计模式有其独特的优点,要活学活用,不要深陷其中,生搬硬套

2.单例设计模式:
整个项目中,有某个或者某些特殊的类,只能创建一个属于该类的对象。
单例类:只能生成一个对象。

3.单例设计模式共享数据分析、解决
面临问题:需要在自己创建的线程中来创建单例类的对象,这种线程可能不止一个。我们可能面临GetInstance()这种成员函数需要互斥。
可以在加锁前判断m_instance是否为空,否则每次调用Singelton::getInstance()都要加锁,十分影响效率。

如果觉得在单例模式new了一个对象,而没有自己delete掉,这样不合理。可以增加一个类中类CGarhuishou,new一个单例类时创建一个静态的CGarhuishou对象,这样在程序结束时会调用CGarhuishou的析构函数,释放掉new出来的单例对象。

4.std::call_once():
函数模板,该函数的第一个参数为标记,第二个参数是一个函数名(如a())。
功能:能够保证函数a()只被调用一次。具备互斥量的能力,而且比互斥量消耗的资源更少,更高效。
call_once()需要与一个标记结合使用,这个标记为std::once_flag;其实once_flag是一个结构,call_once()就是通过标记来决定函数是否执行,调用成功后,就把标记设置为一种已调用状态。

多个线程同时执行时,一个线程会等待另一个线程先执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值