(假设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以来,volatile确保上述代码正确无误。假设我没有可移植的代码。
现在假设我需要用std :: shared_ptr或boost :: shared_ptr替换普通指针,我该如何做同样的事情?如何使shared_ptr易变?我需要另一个易变的旗帜吗?
答案 0 :(得分:4)
使用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;
答案 1 :(得分:3)
自VC ++ 2005以来,volatile确保上述代码是正确的。
不,它没有。 volatile
与线程或原子性无关。
您当前的代码不正确,任何C ++标准都无法保证产生合理的行为。
由于你的假装锁定代码一般不起作用,它肯定不适用于shared_ptr
或其他智能指针。如果你想要更便宜的锁定,请研究无锁编码模式。
答案 2 :(得分:1)
在C ++ 2011中,使用任何显式同步甚至不是必需的。根据6.7 [stmt.dcl]第4段,初始化由系统同步:
如果控件在初始化变量时同时进入声明,则并发执行应等待初始化完成。
这似乎暗示std::shared_ptr<T>
可以这样初始化:
{
static std::shared_ptr<MyType> ptr(new MyType(/*...*/));
// ...
}