共享指针的双重检查锁定
Double-checked Locking for Shared Pointers
免责声明: 我来自 Java 背景,因此,我不知道 C++(和相关库)的内部结构有多少) 工作。
我已经阅读了足够多的资料,知道双重检查锁定是邪恶的,正确和安全地实现单例模式需要适当的工具。
我认为以下代码可能不安全,受编译器重新排序和分配未初始化对象的影响,但我不确定我是否遗漏了一些我不了解该语言的内容。
typedef boost::shared_ptr<A> APtr;
APtr g_a;
boost::mutex g_a_mutex;
const APtr& A::instance()
{
if (!g_a)
{
boost::mutex::scoped_lock lock(g_a_mutex);
if (!g_a)
{
g_a = boost::make_shared<A>();
}
}
return g_a;
}
我相信实际代码是在 C++03 下编译的。
这个实现不安全吗?如果可以,怎么做?
所有这些在现代 C++ 中都是绝对不需要的。单例代码对于除了恐龙之外的任何人都应该像这样简单:
A& A::instance() {
static A a;
return a;
}
在 C++11 及更高版本中 100% 线程安全。
但是,我有一个强制声明:单例是邪恶的反模式,应该永远被禁止。
关于原代码的线程安全
是的,前提是代码不安全。由于读取是在互斥量之外完成的,因此完全有可能对 g_a
自身 的修改是可见的,但对对象 g_a
的修改是不可见的指向。结果,线程将绕过互斥锁定和 return 指向非构造对象的指针。
是的,双重检查锁定模式在古老的语言中是不安全的。我不能比 What's wrong with this fix for double checked locking?:
中的解释做得更好
The problem apparently is the line assigning instance -- the compiler is free to allocate the object and then assign the pointer to it, OR to set the pointer to where it will be allocated, then allocate it.
如果您使用的是 C++11 std::shared_ptr
,您可以在共享指针对象上使用 atomic_load
and atomic_store
,它们保证彼此正确组合并与互斥锁组合;但是如果你使用的是 C++11,你也可以只使用一个动态初始化的 static
变量,它保证是线程安全的。
免责声明: 我来自 Java 背景,因此,我不知道 C++(和相关库)的内部结构有多少) 工作。
我已经阅读了足够多的资料,知道双重检查锁定是邪恶的,正确和安全地实现单例模式需要适当的工具。
我认为以下代码可能不安全,受编译器重新排序和分配未初始化对象的影响,但我不确定我是否遗漏了一些我不了解该语言的内容。
typedef boost::shared_ptr<A> APtr;
APtr g_a;
boost::mutex g_a_mutex;
const APtr& A::instance()
{
if (!g_a)
{
boost::mutex::scoped_lock lock(g_a_mutex);
if (!g_a)
{
g_a = boost::make_shared<A>();
}
}
return g_a;
}
我相信实际代码是在 C++03 下编译的。
这个实现不安全吗?如果可以,怎么做?
所有这些在现代 C++ 中都是绝对不需要的。单例代码对于除了恐龙之外的任何人都应该像这样简单:
A& A::instance() {
static A a;
return a;
}
在 C++11 及更高版本中 100% 线程安全。
但是,我有一个强制声明:单例是邪恶的反模式,应该永远被禁止。
关于原代码的线程安全
是的,前提是代码不安全。由于读取是在互斥量之外完成的,因此完全有可能对 g_a
自身 的修改是可见的,但对对象 g_a
的修改是不可见的指向。结果,线程将绕过互斥锁定和 return 指向非构造对象的指针。
是的,双重检查锁定模式在古老的语言中是不安全的。我不能比 What's wrong with this fix for double checked locking?:
中的解释做得更好The problem apparently is the line assigning instance -- the compiler is free to allocate the object and then assign the pointer to it, OR to set the pointer to where it will be allocated, then allocate it.
如果您使用的是 C++11 std::shared_ptr
,您可以在共享指针对象上使用 atomic_load
and atomic_store
,它们保证彼此正确组合并与互斥锁组合;但是如果你使用的是 C++11,你也可以只使用一个动态初始化的 static
变量,它保证是线程安全的。