双重检查共享指针的锁定
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++11 std::shared_ptr
,则可以在共享指针对象上使用 atomic_load
和 atomic_store
,它们保证彼此正确组合并使用互斥体组成;但如果使用 C++11,您也可以只使用动态初始化的 static
变量,该变量保证是线程安全的。
所有这些都是现代C++绝对没有必要的。对于除了恐龙之外的任何人来说,单例代码都应该如此简单:
A& A::instance() {
static A a;
return a;
}
在 C++11 及更高版本中 100% 线程安全。
但是,我有一个强制性声明:单身人士是邪恶的反模式,应该永远禁止。
关于原始代码的线程安全性
是的,提供的代码不安全。由于读取是在互斥锁之外完成的,因此完全有可能看到对g_a
本身的修改,但对g_a
指向的对象的修改则不可见。因此,线程将绕过互斥锁并返回指向非构造对象的指针。
相关文章:
- 1d 智能指针不适用于语法 (*)++
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 为什么使用 "this" 指针调用派生成员函数?
- 函数向量_指针有不同的原型,我可以构建一个吗
- 使用指针从C++中的数组中获取最大值
- 助记符和指向成员语法的指针
- 嵌入方指针压缩已禁用
- 数组的指针从不分段故障
- C++ 指针的内存地址和指向数组的内存地址如何相同?
- 何时在引用或唯一指针上使用移动语义
- QMetaObject invokeMethod的基于函数指针的语法
- 如何从 std::atomic 中提取指针 T<T>?
- 如何在 C# 中映射双 C 结构指针?
- C++将浮点指针值舍入为小数位数
- 为什么++(*p)更改指针值
- 调整大小后指向元素值的指针unordered_map有效?
- 正在将指针转换为范围
- 双重检查共享指针的锁定
- 标记了 C 中的锁定免费列表的指针
- C++智能指针是否无锁定