使用C++无锁编程实现多线程下的单例模式
贺志国
2023.8.1
在多线程环境下创建一个类的单例对象,要比单线程环境下要复杂很多。下面介绍在多线程环境下实现单例模式的几种方法。
一、尺寸较小的类单例对象创建
如果待创建的单例类SingletonForMultithread内包含的成员变量较少,整个类占用的内存空间较小,则可使用局部静态变量来创建单例对象。C++ 11标准保证在多线程环境下,在第一个线程未完成静态对象的构建前,其他线程必须等待其完成,因此是线程安全的。如果类的尺寸较大,静态变量存储栈区无法容纳该类的单例对象,则禁止使用该方法。例如:64位Linux系统默认栈的最大空间为8 MB,64位Windows系统默认栈的最大空间为1 MB,当待创建的单例对象尺寸接近或超过上述栈的默认存储空间时,如使用该方法创建则会导致程序崩溃。示例代码如下所示:
class SmallSingletonForMultithread {
public:
static SmallSingletonForMultithread& GetInstance() {
static SmallSingletonForMultithread instance;
return instance;
}
private:
SmallSingletonForMultithread() = default;
~SmallSingletonForMultithread() = default;
SmallSingletonForMultithread(const SmallSingletonForMultithread&) = delete;
SmallSingletonForMultithread& operator=(const SmallSingletonForMultithread&) = delete;
SmallSingletonForMultithread(SmallSingletonForMultithread&&) = delete;
SmallSingletonForMultithread& operator=(SmallSingletonForMultithread&&) = delete;
};
二、尺寸较大的类单例对象创建(使用无锁编程来实现)
在实际工作中,由于某些单例类的尺寸较大,静态变量存储栈区无法容纳该单例对象,因此无法使用上述方法来创建单例对象,这时需要使用new在堆区动态创建单例对象。为了避免多线程环境下对于单例对象的抢夺,可使用C++无锁编程来实现。在程序结束时使用atexit(DestoryInstance)来删除单例对象,示例代码如下所示:
#include <atomic>
#include <cassert>
#include <memory>
#include <thread>
#include <vector>
namespace {
constexpr size_t kThreadNum = 2000;
}
class SingletonForMultithread {
public:
static SingletonForMultithread* GetInstance() {
if (!instance_.load(std::memory_order_acquire)) {
auto* new_ptr = new SingletonForMultithread;
SingletonForMultithread* old_ptr = nullptr;
if (!instance_.compare_exchange_strong(old_ptr, new_ptr,
std::memory_order_release,
std::memory_order_relaxed)) {
// If the CAS operation fails, another thread has created a singleton
// object, and it's necessary to delete the temporary object created by
// the current thread.
delete new_ptr;
new_ptr = nullptr;
}
// When the program exits, the function to delete the singleton object
// is called.
atexit(DestoryInstance);
}
return instance_.load(std::memory_order_relaxed);
}
static void DestoryInstance() {
if (instance_.load(std::memory_order_acquire)) {
auto* old_ptr = instance_.load(std::memory_order_relaxed);
SingletonForMultithread

本文介绍了在多线程环境下使用C++的不同方法创建单例对象,包括使用局部静态变量、无锁编程、std::unique_ptr和std::call_once或std::atomic_flag实现线程安全的单例。
2656

被折叠的 条评论
为什么被折叠?



