C++单例模式线程安全版实现

单例模式基本定义:运行时只有一个实例,分为饿汉式(开始就实例化)和懒汉式(调用才实例化),下面实现懒汉式(因为我比较懒O(∩_∩)O~)

单例模式特点:

1.只有唯一全局访问点(单一接口)

2.只能实例化一次(静态变量)

3.不能赋值或者拷贝(把拷贝和赋值重载函数写在private里,或者设为delete)

额外实现:

线程安全(加锁)

防止内存泄漏(智能指针)

C++代码如下

#include <iostream> 
#include <memory> //shared_ptr
#include <mutex>
#include <thread> 
using namespace std;
class Singleton
{
    private:
        Singleton()
        {
            cout << "constructed!" << '\n';
        }

        static mutex mtx;
        static shared_ptr<Singleton> single_instance;//智能指针

    public:

        ~Singleton()
        {
            cout << "destructed!" << '\n';
        }

        Singleton(Singleton&) = delete;
        Singleton* operator=(const Singleton&) = delete;//禁止拷贝与构造

        static shared_ptr <Singleton> getInstance()
        {
            if (single_instance == nullptr)//第一层检验
            {
                cout << "a"<<" ";
                mtx.lock();//上锁
                if (single_instance == nullptr)//第二层检验
                {
                    single_instance = shared_ptr<Singleton>(new Singleton);
                }
                mtx.unlock();//解锁
            }
           return single_instance;
        }
};

shared_ptr<Singleton> Singleton::single_instance = nullptr;//初始化
mutex Singleton::mtx;

void Test()
{
    for (int i = 0; i < 100; i++)
    {
        shared_ptr<Singleton> ptr = Singleton::getInstance();
       // cout << ptr.use_count()<<" ";
    }
}

int main()
{
    thread th1(Test);
    thread th2(Test);

    th1.join();
    th2.join();

    return 0;
}

运行结果1

a constructed!
a destructed!

运行结果2

a a constructed!
destructed!

从运行结果可以看到,两个线程同时尝试初始化Singleton时,只有一个可以成功

结果二是两个线程开始都判断Singleton没有实例化,但是其中一个加了锁并成功实例化,另一个就不能实例化

Q:为什么要用双重判断呢?

第一层判断是为了防止多次加锁,浪费资源

第二层判断是为了防止重复创建实例

Q:单例模式的应用和缺陷

应用场景:只需要一个实例化对象,比如日志系统,GUI组件(整个应用程序只需要一个GUI组件),并且该对象可能会被频繁地销毁和创建

缺陷:全局对象所有子系统都可以调用,增大了耦合性,如果某个系统改变了单例的实例并引发崩溃,很难去维护

其他:单例模式还可以用局部静态变量实现,更加简单,这里不赘述啦

猜你喜欢

转载自blog.csdn.net/qq_30798083/article/details/130605787