C++ 双重锁定解决方案

C++ 双重锁定解决方案,c++,multithreading,thread-safety,C++,Multithreading,Thread Safety,我想惰性地实例化一个ViewportFactory,如下所示: ViewportFactory* RenderObjectFactory::GetViewportFactory() { if (viewportFactory == nullptr) { std::lock_guard<std::mutex> instantiationLockGuard { factoryInstantiationMutex }; if (viewportFac

我想惰性地实例化一个
ViewportFactory
,如下所示:

ViewportFactory* RenderObjectFactory::GetViewportFactory() {
    if (viewportFactory == nullptr) {
        std::lock_guard<std::mutex> instantiationLockGuard { factoryInstantiationMutex };
        if (viewportFactory == nullptr) {
            switch (GetAndCommitRenderingAPISelection()) {
                case 0:
                    ViewportFactory* v = new DirectXViewportFactory { };
                    viewportFactory = v;
                    break;
            }
        }
    }

    return viewportFactory;
}
ViewportFactory*RenderObjectFactory::GetViewportFactory(){
如果(viewportFactory==nullptr){
std::lock_guard实例化lockguard{factoryInstantiationMutex};
如果(viewportFactory==nullptr){
开关(GetAndCommitTrenderInGapiSelection()){
案例0:
ViewportFactory*v=新的DirectXViewportFactory{};
视口工厂=v;
打破
}
}
}
返回视口工厂;
}

这足够安全吗?我的想法是,只要分配
viewportFactory
,只要
新的DirectXViewportFactory
被正确实例化,它就是…

我认为这是不安全的。通过优化
viewportFactory
,仍然可以在调用构造函数之前为已分配但未初始化的内存分配指针。请参见中的示例6

即使是安全的,该代码也不便于维护。当稍后有人出现时,可能是您或完全不熟悉它的人,很容易在错误的位置添加代码,从而引入竞争条件。这些bug很难复制和隔离——性能提升真的值得冒这个风险吗


正如@DieterLücking所提示的,可以使用局部静态变量实现惰性实例化,这在C++11标准中是线程安全的。您必须小心,您的编译器实际上实现了标准的这一部分-对于Visual Studio(因为您似乎在Windows上),这种情况直到发生时才发生。

目前的代码不是线程安全的。编译器可以自由地优化连续的空检查,因为指针从未在同一线程上更改


我认为使用c++11实现这一点的建议方法是使用std::call_一次或使用静态变量。有关示例,请参见。另外:

“足够线程安全”?方法要么是线程安全的,要么不是。为什么viewportFactory不是函数的静态局部?@DieterLücking直到VS2013(2013年11月发布)才在Visual Studio中强制执行局部静态变量的线程安全初始化。OP可能需要使用较旧的编译器生成。