zoukankan      html  css  js  c++  java
  • 七、单例设计模式

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

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

    单例设计模式

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

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

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

    函数判断:如果单例类没有初始化,就初始化呗。=》一个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);
    }
    心之所愿,永不相忘
  • 相关阅读:
    定义 : angular view 和controller 之前的 ng-init 由谁来负责
    pl/sql如何在云端服务器上新建数据库
    oracle连接服务器上数据库
    svn check下来的代码在eclipse中没有run on server
    sql server在修改表结构后不能保存
    用mybatis-generator自动生成代码报“前言中不允许有内容”
    启动Tomact时报failed to start conponent
    spring MVC中controller失效
    maven项目中连接sqlserver和mysql的区别
    DBCP连接池的配置
  • 原文地址:https://www.cnblogs.com/zgll/p/15291541.html
Copyright © 2011-2022 走看看