0

(假设 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 不稳定?我需要另一个 volatile 标志吗?

4

3 回答 3

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;
于 2012-09-22T18:48:35.733 回答
3

从 VC++ 2005 开始,volatile 确保上面的代码是正确的。

不,不是的。volatile与线程或原子性无关。

您当前的代码不正确,任何 C++ 标准都不能保证产生合理的行为。

由于您的假装锁定代码通常不起作用,因此它肯定不会在shared_ptr其他智能指针上起作用。如果您想要更便宜的锁定,请查看无锁编码模式。

于 2012-09-22T18:41:08.650 回答
1

在 C++ 2011 中,甚至不需要使用任何显式同步。根据 6.7 [stmt.dcl] 第 4 段,初始化由系统同步:

如果在变量初始化时控制同时进入声明,则并发执行将等待初始化完成。

这似乎意味着std::shared_ptr<T>可以像这样初始化:

{
    static std::shared_ptr<MyType> ptr(new MyType(/*...*/));
    // ...
}
于 2012-09-22T20:11:49.133 回答