双锁定解决方案

Double Locking Workaround

本文关键字:解决方案 锁定      更新时间:2023-10-16

我想惰性实例化一个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;
}

是否足够线程安全?我的想法是,只有在new DirectXViewportFactory被正确实例化后才分配viewportFactory,它是…

当前的代码不是线程安全的。编译器可以自由地优化连续的空检查,因为指针在同一个线程上永远不会改变。

我认为在c++11中建议使用std::call_once或使用静态变量来完成此操作。请看这里的例子。另外:参考

我不相信这是安全的。通过优化,仍然可以在调用构造函数之前为viewportFactory分配一个指向已分配但未初始化的内存的指针。参见c++中的例6和双重检查锁定的危险。

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

正如@ dieterl cking提示的那样,惰性实例化可以用一个局部静态变量来实现,这在c++ 11标准中是线程安全的。你必须小心你的编译器实际上实现了标准的这一部分-对于Visual Studio(因为你似乎是在Windows上),这直到Visual Studio 2013才发生。