曾格的github

七、单例设计模式

设计模式:代码的一些写法:程序灵活,维护起来可能方便,但是别人接管比较麻烦。

设计模式肯定有它独特的有点,要活学活用,不要深陷其中,不要为了用设计模式而用设计模式。

单例设计模式

单例类:整个项目只能创建一个对象。

单线程单例步骤:构造函数初始化 =》静态私有成员变量 =》公有静态函数,返回类对象指针。

那怎么释放这个类对象=》类中再使用一个类。

函数判断:如果单例类没有初始化,就初始化呗。=》一个null判断

初始化要加锁:

#include <thread>
#include <iostream>
#include <list>
#include <mutex>
using namespace std;
std::mutex resource_mutex;
 
class MyCAS {
private:
    MyCAS() {} //私有化构造函数
 
private:
    static MyCAS *m_instance;
    
 
public:
    static MyCAS *GetInstance() {
        std::unique_lock<std::mutex> mymutex(resource_mutex); 
        //此方法可行,但是效率太低,这个 锁 实际上只用于第一次创建MyCAS时
        //但是,之后每次执行时都必须调用它
        if (m_instance == nullptr) {
            m_instance = new MyCAS();
            static CCarhuishou cl;
        }
        return m_instance;
    }
 
    class CCarhuishou { //用来释放对象
    public:
        ~CCarhuishou() {
            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 *pa = MyCAS::GetInstance();
    cout << "我的线程结束了" << endl;
}
 
int main() {
    //这里是两个线程,所以是两个通路同时执行GetInstance()
    //这时存在 m_instance = new MyCAS(); 被执行多次的可能
    std::thread myobj1(mythread);
    std::thread myobj2(mythread);
}

是这样有个问题:

  很多线程都调用这个静态函数,那就每次都需要创建锁,锁开销很大,因此在加锁时需要再判断一次单例类是否为空,为空就加锁创建对象了。

  =》那里面的锁是不是可以不要了

  可能存在这样的情况:就是线程A第一个判断过了,然后申请锁失败了,就等着;等的过程线程B把对象创建了,此时线程A获得锁,不加判断的话会重复创建。

#include <thread>
#include <iostream>
#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 CCarhuishou cl;
            }
        }
        return m_instance;
    }
 
    class CCarhuishou { //用来释放对象
    public:
        ~CCarhuishou() {
            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 *pa = MyCAS::GetInstance();
    cout << "我的线程结束了" << endl;
}
 
int main() {
    //这里是两个线程,所以是两个通路同时执行GetInstance()
    //这时存在 m_instance = new MyCAS(); 被执行多次的可能
    std::thread myobj1(mythread);
    std::thread myobj2(mythread);
}

std::call_once()函数模板

它的功能是能够保证函数a只被调用一次。它具备互斥量这种能力,而且效率上,比互斥量消耗的资源更少;

call_once()需要与一个标记结合使用,这个标记 std::once_flag;其实 once_flag 是一个结构

call_once()就是通过这个表姐来决定对应的函数a()是否执行,调用call_once()成功后,call_once()就把这个标记设置为一种已调用状态。

#include <thread>
#include <iostream>
#include <list>
#include <mutex>
using namespace std;
std::mutex resource_mutex;
std::once_flag g_flag;
 
class MyCAS {
private:
    MyCAS() {} //私有化构造函数
 
    static void CreateInstance() {
        m_instance = new MyCAS();
        static CCarhuishou cl;
    }
 
private:
    static MyCAS *m_instance;
    
 
public:
    static MyCAS *GetInstance() {
        std::call_once(g_flag, CreateInstance); //这里可以把 g_flag 看成一把锁
        return m_instance;
    }
 
    class CCarhuishou { //用来释放对象
    public:
        ~CCarhuishou() {
            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 *pa = MyCAS::GetInstance();
    cout << "我的线程结束了" << endl;
}
 
int main() {
    //这里是两个线程,所以是两个通路同时执行GetInstance()
    //这时存在 m_instance = new MyCAS(); 被执行多次的可能
    std::thread myobj1(mythread);
    std::thread myobj2(mythread);
}

 

posted @ 2021-09-16 00:18  曾格  阅读(40)  评论(0编辑  收藏  举报
Live2D