编写线程安全的单例模式

in 后端技术 with 0 comment view 57 times
 graph LR;
单例设计模式-->主要逻辑;
单例设计模式-->注意事项;
单例设计模式-->可继承的单例代码;
单例设计模式-->父类调用子类;
单例设计模式-->参考文献;
click 单例设计模式 "#menu_index_1"
click 主要逻辑 "#menu_index_2"
click 注意事项 "#menu_index_3"
click 可继承的单例代码 "#menu_index_4"
click 父类调用子类 "#menu_index_5"
click 参考文献 "#menu_index_6"

单例设计模式

主要逻辑

#include <iostream>
#include <mutex>
using namespace std;
class Singleton
{
private:
    static Singleton* instance;
    static std::mutex kMutex;
private:
    Singleton() { };
    ~Singleton() { };
    Singleton(const Singleton&);
    Singleton& operator=(const Singleton&);
private:
    class Deletor {
    public:
        ~Deletor() {
            if(Singleton::instance != NULL)
                delete Singleton::instance;
        }
    };
    static Deletor deletor;
public:
    static Singleton* getInstance() {
        if(instance == NULL) {
            kMutex.lock();
            instance = new Singleton();
            cout << "获取单例" << endl;
            kMutex.unlock();
        }
        return instance;
    }
};
// init static member
Singleton* Singleton::instance = NULL;
std::mutex Singleton::kMutex;

int main(){
// Singleton::m_pInstance = NULL;
Singleton* p1 = Singleton::getInstance();
Singleton* p2 = p1->getInstance();
Singleton & ref = * Singleton::getInstance();
}

注意事项

  1. 静态成员变量声明需要在 .cpp 文件中初始化;
  2. 多线程环境下需要加锁 kMutex.lock()
  3. 继承过单例子模式的类,不能直接再被继承,因为子类获取单例会直接拿到父类的实体,如果需要继承则需要在子类中重写单例逻辑

可继承的单例代码

  1. Singleton.h 文件
#ifndef _SINGLETON_H_
#define _SINGLETON_H_

#include <memory>

class Singleton
{
public:
    static Singleton& GetInstance();

private:
    Singleton();
    ~Singleton();

    // Use auto_ptr to make sure that the allocated memory for instance
    // will be released when program exits (after main() ends).
    static std::auto_ptr<Singleton> s_instance;
    friend class std::auto_ptr<Singleton>;

    Singleton(const Singleton&);
    Singleton& operator =(const Singleton&);
};

#endif
  1. Singleton.cpp 文件
#include "Singleton.h"
#include <iostream>
#include <boost/thread.hpp>

using namespace std;
using namespace boost;

auto_ptr<Singleton> Singleton::s_instance;

Singleton::Singleton()
{
    cout << "Construct Singleton" << endl;
}

Singleton::~Singleton()
{
    cout << "Destruct Singleton" << endl;
}

Singleton& Singleton::GetInstance()
{
    static mutex s_mutex;
    if (s_instance.get() == NULL)
    {
        mutex::scoped_lock lock(s_mutex);
        if (s_instance.get() == NULL)
        {
            s_instance.reset(new Singleton());
        }
        // 'lock' will be destructed now. 's_mutex' will be unlocked.
    }
    return *s_instance;
}

父类调用子类

#include <iostream>
#include <regex>
using namespace std;

class Base
{
public:
    virtual void fun()
    {
        std::cout << base << std::endl;
    }
private:
    int base = 10;
};

class Derived : public Base
{
public:
    virtual void fun()
    {
        std::cout << base<< std::endl;
    }
private:
    int base = 12;
};


int main() {
    Derived* d = new Derived;
    Base* bb = d;
    Base* base = new Derived;
    cout << "base obj name:\t" << typeid(base).name() << endl;
    base->fun();    //该结果输出为: "12" 子类的变量
    cout << "父类指针:"<< typeid(bb).name() << "\t子类指针:" << typeid(d).name() << endl;
    // 结果为: 父类指针:P4Base    子类指针:P7Derived
    return 0;
}
  1. 被调用的函数在父类中需要声明 virtual (必须)
  2. 类型是父类,但是方法和变量均是子类的
  3. 使用指针也可以调用,见: https://blog.csdn.net/Huoon/article/details/67819045

参考文献

  1. <可以继承的 C++ Singleton 基类>: https://blog.gocalf.com/cpp-singleton
  2. <知乎:C++ 单例模式> https://zhuanlan.zhihu.com/p/37469260
  3. <线程安全的单例模式> https://www.cnblogs.com/ccdev/archive/2012/12/19/2825355.html
Responses