如何使用双重检查锁来初始化shared_ptr
How to use double checked lock to init a shared_ptr
>(假设VC++ 2010:(1)可以使用/volatile:ms,(2)还没有std::atomic,(3)没有线程安全的静态变量初始化,(4)没有std::call_once)
如果我有一个普通的 C 指针,我可以暗示以下双重检查锁定模式,以避免每次锁定的成本:
static volatile void * ptr = nullptr;
//...
if ( ptr == nullptr)
{
// Acquire Lock
if (ptr == nullptr)
{
// some code
// ptr = ...; // init ptr
}
// Release Lock
}
// ....
从 VC++ 2005 开始,易失性确保上述代码是正确的。假设我对代码不可移植感到满意。
现在假设我需要用 std::shared_ptr 或 boost::shared_ptr 替换普通指针,我将如何做同样的事情?如何使这种shared_ptr波动?我是否需要另一个易失性标志?
在 C++11 中,有用于 shared_ptr
的原子访问器函数。要编写使用 shared_ptr
的双重检查锁,请使用以下访问器:
static std::shared_ptr<MyType> ptr;
if (std::atomic_load(ptr) == 0) {
// lock the lock
if (std::atomic_load(ptr) == 0) {
std::shared_ptr<MyType> local_ptr(new MyType);
std::atomic_store(ptr, local_ptr);
}
// unlock the lock
}
return ptr;
从 VC++ 2005 开始,易失性确保上述代码是正确的。
不,它没有。 volatile
与线程或原子性无关。
您当前的代码不正确,并且任何C++标准都不能保证产生合理的行为。
由于您的假装锁定代码通常不起作用,因此它肯定不适用于shared_ptr
或其他智能指针。如果您想要更便宜的锁定,请查看无锁定编码模式。
在 2011 C++中,甚至不需要使用任何显式同步。根据 6.7 [stmt.dcl] 第 4 段,初始化由系统同步:
如果在初始化变量时控件并发进入声明,则并发执行应等待初始化完成。
这似乎暗示std::shared_ptr<T>
可以像这样初始化:
{
static std::shared_ptr<MyType> ptr(new MyType(/*...*/));
// ...
}
相关文章:
- 是否可以初始化不可复制类型的成员变量(或基类)
- C++使用整数的压缩数组初始化对象
- C++初始化基类
- 多成员Constexpr结构初始化
- 复制列表初始化的隐式转换的等级是多少
- 内联映射初始化的动态atexit析构函数崩溃
- 如何在C++中初始化嵌套类中的2个memeber
- 如何声明特征矩阵,然后通过嵌套循环初始化它
- 没有用于初始化C++中的变量模板的匹配构造函数
- 在未初始化映射的情况下,将值插入到映射的映射中
- C++成员初始化
- 为什么在C++中首先初始化成员类
- 同时具有"聚合初始化"和"模板推导"
- 初始化具有非默认构造函数的std::数组项的更好方法
- 是否可以在编译时初始化数组,以便在运行时不会花费时间?
- 我可以使用条件运算符初始化C风格的字符串文字吗
- 在C和C++中初始化结构中的数组
- 标准是否使用多余的大括号(例如 T{{{10}}})定义列表初始化?
- 在函数内部的声明中初始化数组,并在外部使用它
- 继承:构造函数,初始化C++11中基类的类C数组成员