正确写法
该写法在第一次调用get_instance()
后构造该实例,线程安全。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class object{ public: ~object() = default; static std::unique_ptr<object>& get_instance(); private: object() = default; };
std::unique_ptr<object>& object::get_instance(); static std::unique_ptr<object> instance; static std::once_flag flag; std::call_once(flag, [&](){ instance = std::make_unique<object>();
}); return instance; }
|
其他写法比较
最简单的写法: 线程不安全
由于new object()
这个构造的过程需要时间,所以可能造成两个线程同时获取到instance
变量为空指针。从而导致实例化两次,从未导致硬件驱动加载两次,而导致崩溃。
1 2 3 4 5 6 7
| object* object::get_instance() { object* instance = nullptr; if(instance == nullptr) { instance = new object(); } return instance; }
|
double check
写法: 看起来线程安全,其实有条件竞争。
在#1
和#2
处,可能发生一个线程正在对instance
变量赋值(写操作), 而另一个线程在进行在进行判断instance
变量是否为空(读操作),从而导致条件竞争,而导致崩溃。
1 2 3 4 5 6 7 8 9 10 11
| object* object::get_instance(){ static std::mutex mt; volatile object* instance = nullptr; if(instance == nullptr) { std::lock_guard<std::mutex> lock(mt); if(instance == nullptr) { instance = new object(); } } return instance; }
|