目标: 写一个分配内存的类,并用单利模式来进行管理
方案一双重检查锁定
class CPUDeviceAllocatorFactory {
public:
static std::shared_ptr<CPUDeviceAllocator> get_instance() {
if (instance == nullptr) { // First check (no locking)
std::lock_guard<std::mutex> lock(mutex_);
if (instance == nullptr) { // Second check (with locking)
instance = std::make_shared<CPUDeviceAllocator>();
}
}
return instance;
}
private:
static std::shared_ptr<CPUDeviceAllocator> instance;
static std::mutex mutex_;
};
std::shared_ptr<CPUDeviceAllocator> CPUDeviceAllocatorFactory::instance = nullptr;
std::mutex CPUDeviceAllocatorFactory::mutex_;
方案二使用std::call_once
std::call_once
保证某个操作只会执行一次,并且是线程安全的。可以用于初始化单例实例。
#include <mutex>
class CPUDeviceAllocatorFactory {
public:
static std::shared_ptr<CPUDeviceAllocator> get_instance() {
std::call_once(flag, []() {
instance = std::make_shared<CPUDeviceAllocator>();
});
return instance;
}
private:
static std::shared_ptr<CPUDeviceAllocator> instance;
static std::once_flag flag;
};
std::shared_ptr<CPUDeviceAllocator> CPUDeviceAllocatorFactory::instance = nullptr;
std::once_flag CPUDeviceAllocatorFactory::flag;
方案三静态函数变量
class CPUDeviceAllocatorFactory {
public:
static std::shared_ptr<CPUDeviceAllocator> get_instance() {
static std::shared_ptr<CPUDeviceAllocator> instance = std::make_shared<CPUDeviceAllocator>();
return instance;
}
};
代码分析
-
静态局部变量:
instance
是get_instance
函数的一个静态局部变量,这意味着它只会在第一次调用get_instance
时被初始化,而后续对get_instance
的调用都将返回这个已经初始化的对象。 -
线程安全:在 C++11 标准中,静态局部变量的初始化是线程安全的。这意味着多个线程同时访问
get_instance
时,静态局部变量instance
只会被正确地初始化一次,其他线程会等待初始化完成后再获取该实例。 -
简洁性:使用静态局部变量的方式相较于双重检查锁定或
std::call_once
的方式更为简洁,不需要额外的锁或标记位。
总结
使用静态函数变量是实现线程安全单例模式的简洁且有效的方式,特别是在 C++11 及更高版本中,它避免了使用锁定机制的复杂性,同时确保了初始化的线程安全性。因此,这种方法是一种推荐的实现方式。