并发多线程7单例设计模式共享数据分析、解决,

第七节 单例设计模式共享数据分析、解决,call_once

1.设计模式

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

2.单例设计模式:

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

3.单例设计模式共享数据分析、解决

面临问题:需要在自己创建的线程中来创建单例类的对象,这种线程可能不止一个。我们可能面临

getInstance()这种成员函数需要互斥。

可以在加锁前判断m_instance是否为空,否则每次调用

MyClass::getInstance()都要加锁,十分影响效率。


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

using namespace std;
//懒汉模式
mutex mymutex;
class MyClass
{
public:
    static MyClass *getInstance()
    {
        //双重锁定
        if (m_instance == NULL)
        {
            //为了线程安全加锁
            unique_lock<mutex> myunique(mymutex);
            if (m_instance == NULL)
            {    
                m_instance = new MyClass();
                static MyClassHuiShou cl;//回收对象
            }
        }
        return m_instance;
    }
    void fun()
    {
        cout << "测试" << endl;
    }
    class MyClassHuiShou//类中套类,释放对象
    {
    public:
        ~MyClassHuiShou()
        {
            if (MyClass::m_instance)
            {
                delete MyClass::m_instance;
                MyClass::m_instance = NULL;
            }
        }

    };
private:
    MyClass(){}//私有化构造函数
private:
    static MyClass* m_instance;
};
//类静态成员初始化
MyClass* MyClass::m_instance = NULL;

//饿汉模式
class Singleton2 {
public:
    static Singleton2* getInstance() {
        return instance;
    }
private:
    Singleton2() {}
    static Singleton2* instance;
};
Singleton2* Singleton2::instance = new Singleton2;

int main()
{
    MyClass* p_a = MyClass::getInstance();//创建一个对象
    p_a->fun();
    MyClass::getInstance()->fun();

    MyClass* singer = MyClass::getInstance();
    MyClass* singer2 = MyClass::getInstance();
    if (singer == singer2)
        cout << "二者是同一个实例" << endl;
    else
        cout << "二者不是同一个实例" << endl;

    cout << "----------        以下 是 饿汉式    ------------" << endl;
    Singleton2* singer3 = Singleton2::getInstance();
    Singleton2* singer4 = Singleton2::getInstance();
    if (singer3 == singer4)
        cout << "二者是同一个实例" << endl;
    else
        cout << "二者不是同一个实例" << endl;

    return 0;

}

 

4.std::call_once():

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

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

once_flag g_flag;
class Singleton
{
public:
    static void CreateInstance()//call_once保证其只被调用一次
    {
        instance = new Singleton;
    }
    //两个线程同时执行到这里,其中一个线程要等另外一个线程执行完毕
    static Singleton * getInstance() {
         call_once(g_flag, CreateInstance);
         return instance;
    }
private:
    Singleton() {}
    static Singleton *instance;
};
Singleton * Singleton::instance = NULL;

 可以在主线程先创建单一对象,避免子线程间的访问影响。

 


原文链接:https://blog.csdn.net/qq_38231713/article/details/106092538

posted @ 2022-08-31 16:58  〉外圆内方〈  阅读(49)  评论(0)    收藏  举报