c++ 11中的双重检查锁定
Double-checked locking in C++11?
下面是来自http://www.ibm.com/developerworks/java/library/j-dcl/index.html
的Java示例问题public static Singleton getInstance()
{
if (instance == null) //#4
{
synchronized(Singleton.class) { //#1
if (instance == null) //#2
instance = new Singleton(); //#3
}
}
return instance;
}
这似乎是不安全的,因为#3可以在构造函数执行之前将instance设置为非空,因此当另一个线程检查#4上的实例时,它将不是空的,并返回一个没有正确构造的实例。
显然,使用函数变量没有帮助,因为它可能会被优化,或者只是以一种方式执行,当我们不希望它将值设置为instance时。
我认为最简单的方法是有一个函数new Singleton();
,所以它在分配给实例之前完成。现在的问题是我如何告诉c++一个函数不应该内联?我认为 Singleton* make_singleton() volatile
应该这样做,但我肯定我错了。
我将暂时忽略单例的位,并假设您需要它用于惰性初始化,而不是用于像单例这样愚蠢的东西。
我建议忘记双重检查锁定。对于这种情况,c++提供了一个非常有用的工具,即std::call_once
,所以请使用它。
template <typename T>
struct lazy {
public:
// needs constraining to prevent from doing copies
// see: http://flamingdangerzone.com/cxx11/2012/06/05/is_related.html
template <typename Fun>
explicit lazy(Fun&& fun) : fun(std::forward<Fun>(fun)) {}
T& get() const {
std::call_once(flag, [this] { ptr.reset(fun()); });
return *ptr;
}
// more stuff like op* and op->, implemented in terms of get()
private:
std::once_flag flag;
std::unique_ptr<T> ptr;
std::function<T*()> fun;
};
// --- usage ---
lazy<foo> x([] { return new foo; });
这正是原子的设计目的。通过将结果存储到原子中,您知道编译器不能在原子设置之后对任何关键存储或操作进行排序。原子既用于发出处理器指令原语,以确保必要的顺序一致性(例如,跨内核的缓存一致性),也用于告诉编译器必须保留哪些语义(从而限制它可以执行的重排序类型)。如果在这里使用原子,则函数是否内联并不重要,因为编译器所做的任何内联都必须保留原子本身的语义。
您可能也有兴趣研究std::call_once
,这也是为这种情况而设计的,更具体地说,是针对多个线程可能需要完成某些事情的情况,但恰好其中一个应该这样做。
相关文章:
- 如何检查线程是否锁定
- 仔细检查锁定问题,c++
- 通过检查条件并重新检查来获取锁定
- Boost upgrade_lock和DCLP(双重检查锁定模式)
- 双重检查和锁定模式在c++(而不是11)中有效吗
- 我的双重检查锁定模式实现是否正确?
- mutex::lock() 检查一次解锁状态是否已经被另一个线程锁定?
- C++与双重检查锁定的危险:变通方法
- C++11:对延迟初始化进行安全的双重检查锁定.可能的
- C++:检查计算机是否已锁定
- 这是否可以兑换线程安全的双重检查锁定模式
- 双重检查共享指针的锁定
- 仔细检查锁定值变为空
- 通过双重检查锁定模式实现call_once
- 线程安全惰性初始化:静态vs std::call_once vs双重检查锁定
- 这是双重检查锁定的有效替代方案吗
- 这个解决方案对MSVC的双重检查锁定错误和函数静态有什么问题?
- c++ 11中的双重检查锁定
- 为双重检查锁定提供适当的编译器内在特性
- 这是正确的 C++11 双检查锁定shared_ptr版本吗?