【发布时间】:2020-05-08 12:57:06
【问题描述】:
这是一段 DCL(双重检查锁定)代码,由 C++ 中的“获取-释放”语义实现。代码如下:
std :: atomic <Singleton *> Singleton :: m_instance;
std :: mutex Singleton :: m_mutex;
Singleton * Singleton :: getInstance () {
Singleton * tmp = m_instance.load (std :: memory_order_acquire); // 3
if (tmp == nullptr) {
std :: lock_guard <std :: mutex> lock (m_mutex);
tmp = m_instance.load (std :: memory_order_relaxed);
if (tmp == nullptr) {
tmp = new Singleton; // 1
m_instance.store (tmp, std :: memory_order_release); // 2
}
}
return tmp;
}
在https://en.cppreference.com/w/cpp/atomic/memory_order上,memory_order_release的解释是: 具有此内存顺序的存储操作执行释放操作:在此存储之后,当前线程中的任何读取或写入都不能重新排序。当前线程中的所有写入在获取相同原子变量的其他线程中都是可见的。
我的理解是:load-store,store-store不能重排,但没说other-store不能重排。
所以我认为:'1'不仅包括读写指令,还包括调用指令,那么调用指令可能在'2'后面重新排序;那么 '3' 可能会得到一个不安全的 'tmp' 指针。
让我再描述一下上面的段落:
Disassemble ‘1’ into the following two possible pseudo-instructions:
tmp = allocate ();
call Singleton constructor (tmp); // 4
我认为“4”可能会在“2”之后重新排序。一个线程执行‘2’后,另一个线程完成‘3’并获得tmp指针。此时tmp指针是一个不安全的Singleton指针。
所以我有一个问题:上面的代码是线程安全的吗?
【问题讨论】:
-
FWIW,你可以通过
Singleton& Singleton :: getInstance () { static Singleton instance; return instance; }获得所有这些内容 -
@NathanOliver 没错,c++11 保证了静态局部变量的线程安全。但我想知道这段代码是否线程安全?
标签: c++ multithreading c++11