C++ 如何使用双重检查锁初始化共享\u ptr

C++ 如何使用双重检查锁初始化共享\u ptr,c++,c++11,locking,shared-ptr,lazy-initialization,C++,C++11,Locking,Shared Ptr,Lazy Initialization,假设VC++2010:1可以使用/volatile:ms,2没有std::atomic,3没有线程安全静态变量初始化,4没有std::call_ 如果我有一个普通的C指针,我可以执行以下双重检查锁定模式,以避免每次锁定的开销: static volatile void * ptr = nullptr; //... if ( ptr == nullptr) { // Acquire Lock if (ptr == nullptr) { // some code

假设VC++2010:1可以使用/volatile:ms,2没有std::atomic,3没有线程安全静态变量初始化,4没有std::call_

如果我有一个普通的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\u ptr或boost::shared\u ptr替换普通指针,我将如何做同样的事情?如何使共享的ptr不稳定?我需要另一个易失性标志吗

自VC++2005以来,volatile确保上述代码是正确的

不,没有。volatile与线程或原子性无关

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


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

对于C++11,有用于共享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;

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

如果控件在初始化变量时并发输入声明,则并发执行应等待初始化完成

这似乎意味着std::shared\u ptr可以这样初始化:

{
    static std::shared_ptr<MyType> ptr(new MyType(/*...*/));
    // ...
}

不,没有。双重检查锁定不好。是什么让您相信volatile使代码正确?如果您更改static volatile void*ptr=nullptr;to std::atomic ptr=nullptr;双重检查锁定将起作用。这假设C++11。@Daniel:volatile保证了VC++2005+中的内存屏障。因此,自VC++2005以来,volatile确保上述代码是正确的。;-]是的,我确实假设/volatile:ms与VC++。因此,代码在标准C++中是不可移植的,甚至是正确的。对不起,没有说清楚。我的问题应该是如何用STD::SydDypPTR或Booo::SydDypTR在VS2010中,其中STD::原子还没有可用。在VisualC++中,OP特别提到,Fravy保证了完整的内存栅栏。如果问题是关于标准C++,你完全正确,但我不觉得这就是问题所在。我应该清楚,这是关于使用/volatile:ms的VC++特定代码。因此,上面的代码是正确的。std::atomic将是理想的。很遗憾,我需要使用VS2010。谢谢。然而,抱歉,这个功能甚至不在VC2012中。如果我错了,请纠正我。另外,1它是否使用延迟初始化?2如果在调用ctor之前,我需要在//some代码部分中包含一些代价高昂的逻辑,那么它仍然不理想。这是一种惰性初始化,您需要在某个时候进行代价高昂的初始化。如果初始化不适合构造函数,则可以调用返回std::shared_ptr的函数。该实现将应用类似std::call_的东西一次,以确保线程在初始化期间被正确阻止,并且在初始化之后被阻止的程度最小。我还不知道是否有编译器实现了这个功能。我仍然认为指出它是如何正确的是有用的。@ Loistin翻译:你是正确的Re:VC++ 2012 -根据N2660没有实现。