C++实现线程安全单例类(可运行)

心血来潮手撕一下线程安全的单例类,做项目的时候写过单例,今天自己动手写发现之前写的并不对。下面参考了小林 coding 的代码,针对加锁的懒汉模式,自己加了一个 AutoRelease 的内部类,可以自动释放单例类的实例资源。

加锁-懒汉模式

懒汉模式:系统运行中实例并不存在,只有当需要使用该实例时,才会去创建并使用实例。

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

#include <unistd.h>

using namespace std;

class Singleton {
public:
    static Singleton* get_instance();
    void print();

private:
    friend class AutoRelease;
    Singleton();
    ~Singleton();
    Singleton(const Singleton& signal) = delete;
    const Singleton& operator=(const Singleton& signal) = delete;

private:
    static Singleton *m_Instance;
    static std::mutex m_Mutex;

private:
    class AutoRelease {
    public:
        AutoRelease() {
            std::cout << "AutoRelease()" << std::endl;
        }
        ~AutoRelease() {
            std::unique_lock<std::mutex> lock(m_Mutex);
            if (m_Instance) {
                delete m_Instance;
                m_Instance = nullptr;
            }
            std::cout << "~AutoRelease()" << std::endl;
        }
    };

private:
    static AutoRelease m_At;
};

Singleton *Singleton::m_Instance = nullptr;
std::mutex Singleton::m_Mutex;
Singleton::AutoRelease Singleton::m_At;

Singleton* Singleton::get_instance() {
    if (m_Instance == nullptr) {
        std::unique_lock<std::mutex> lock(m_Mutex);
        if (m_Instance == nullptr) {
            m_Instance = new Singleton;
        }
    }

    return m_Instance;
}

void Singleton::print() {
    std::cout << "addr: " << this << std::endl;
}

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

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

// operator func
void test() {
    Singleton::get_instance()->print();
}

int main() {
    // create three threads
    thread t1(test);
    thread t2(test);
    thread t3(test);

    // threads joined
    t1.join();
    t2.join();
    t3.join();

    return 0;
}

局部静态变量-懒汉模式(推荐)

在 C++11 内部静态变量是线程安全的,该方法实现的代码量最少。

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

#include <unistd.h>

using namespace std;

class Singleton {
public:
    static Singleton& get_instance();
    void print();

private:
    Singleton();
    ~Singleton();
    Singleton(const Singleton& signal) = delete;
    const Singleton& operator=(const Singleton& signal) = delete;
};

Singleton& Singleton::get_instance() {
    static Singleton singal;  // static var
    return singal;
}

void Singleton::print() {
    std::cout << "addr: " << this << std::endl;
}

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

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

// operator func
void test() {
    Singleton::get_instance().print();
}

int main() {
    // create three threads
    thread t1(test);
    thread t2(test);
    thread t3(test);

    // threads joined
    t1.join();
    t2.join();
    t3.join();

    return 0;
}

饿汉模式

饿汉模式:在程序运行时就创建实例,需要使用的话可直接调用,本身就是线程安全的。

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

#include <unistd.h>

using namespace std;

class Singleton {
public:
    static Singleton* get_instance();
    void print();

private:
    friend class AutoRelease;
    Singleton();
    ~Singleton();
    Singleton(const Singleton& signal) = delete;
    const Singleton& operator=(const Singleton& signal) = delete;

private:
    static Singleton *g_Instance;

private:
    class AutoRelease {
        public:
            AutoRelease() {
                std::cout << "AutoRelease()" << std::endl;
            }
            ~AutoRelease() {
                if (g_Instance) {
                    delete g_Instance;
                    g_Instance = nullptr;
                }
                std::cout << "~AutoRelease()" << std::endl;
            }
    };

private:
    static AutoRelease m_At;
};

/* create an instance when code runs */
Singleton *Singleton::g_Instance = new Singleton;
Singleton::AutoRelease Singleton::m_At;

Singleton* Singleton::get_instance() {
    return g_Instance;
}

void Singleton::print() {
    std::cout << "addr: " << this << std::endl;
}

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

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

// operator func
void test() {
    Singleton::get_instance()->print();
}

int main() {
    // create three threads
    thread t1(test);
    thread t2(test);
    thread t3(test);

    // threads joined
    t1.join();
    t2.join();
    t3.join();

    return 0;
}
#C++##暑期实习#
全部评论
cpp 11有block static,都不用锁,可以实现线程安全
2 回复 分享
发布于 2023-03-11 00:19 江苏
老哥,你看知乎上有个实现c11的文章,使用局部静态变量来
点赞 回复 分享
发布于 2023-03-11 13:33 福建
粽call_once结合once_flag实现
点赞 回复 分享
发布于 2023-03-23 00:11 湖北
我一直都是用局部静态的单例写法,但是面试被问到这样还有什么问题,我猜还是涉及到资源释放的问题
点赞 回复 分享
发布于 2023-03-29 00:17 陕西

相关推荐

最近和朋友聊天,她说了句让我震惊的话:"我发现我连周末点外卖都开始'最优解'了,一定要赶在高峰期前下单,不然就觉得自己亏了。"这不就是典型的"班味入侵"吗?工作思维已经渗透到生活的方方面面。
小型域名服务器:啊?我一直都这样啊?我还以为是我爱贪小便宜呢?每次去实验室都得接一杯免费的开水回去,出门都得规划一下最短路径,在宿舍就吃南边的食堂,在实验室就吃北边的食堂,快递只有顺路的时候才取。
点赞 评论 收藏
分享
专心打鱼:互联网搬运工,贴子都要偷
点赞 评论 收藏
分享
10 50 评论
分享
牛客网
牛客企业服务