Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/130.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 这是双重检查锁定的有效替代方案吗?_C++_Multithreading_Thread Safety - Fatal编程技术网

C++ 这是双重检查锁定的有效替代方案吗?

C++ 这是双重检查锁定的有效替代方案吗?,c++,multithreading,thread-safety,C++,Multithreading,Thread Safety,我想在多线程程序中使用单例模式。双重检查锁定方法似乎适合其效率,但这种方法是坏的,不容易得到正确的 我编写了以下代码,希望它可以作为双重检查锁定的替代方案。它是线程安全的单例模式的正确实现吗 static bool created = false; static Instance *instance = 0; Instance *GetInstance() { if (!created) { Lock lock; // acquire a lock, parame

我想在多线程程序中使用单例模式。双重检查锁定方法似乎适合其效率,但这种方法是坏的,不容易得到正确的

我编写了以下代码,希望它可以作为双重检查锁定的替代方案。它是线程安全的单例模式的正确实现吗

static bool created = false;
static Instance *instance = 0;

Instance *GetInstance() {
    if (!created) {
        Lock lock;    // acquire a lock, parameters are omitted for simplicity
        if (!instance) {
            instance = new Instance;
        } else {
            created = true;
        }
    }
    return instance;
}
第一个调用将创建一个实例。第二个调用将设置为true。最后,所有其他调用将返回一个初始化良好的实例


它与双重检查锁定具有相同的可靠性。 你可以通过“三重检查”,甚至“四重检查”得到更多,但完全的可靠性是不可能的

请注意,声明局部静态变量将使编译器实现自己的逻辑

#include<memory>
#include "Instance.h" //or whatever...

Instance* GetInstance()
{
    static std::unique_ptr<Instance> p(new Instance);
    return p.get();
}
#包括
#包括“Instance.h”//或其他内容。。。
实例*GetInstance()
{
静态std::unique_ptr p(新实例);
返回p.get();
}
如果编译器配置为多线程环境,那么它应该使用互斥来保护静态p,并在第一次调用初始化p时管理锁。它还应该将p销毁链接到“at_exit”链的尾部,以便在程序结束时执行适当的销毁

[编辑] 由于这是C++11的要求,并且仅在某些C++03预标准中实现,请检查编译器实现和设置


现在,我只能确保Mingw4.6已经开启,VS2010已经做到了。

它具有与双重检查锁定相同的可靠性。 你可以通过“三重检查”,甚至“四重检查”得到更多,但完全的可靠性是不可能的

请注意,声明局部静态变量将使编译器实现自己的逻辑

#include<memory>
#include "Instance.h" //or whatever...

Instance* GetInstance()
{
    static std::unique_ptr<Instance> p(new Instance);
    return p.get();
}
#包括
#包括“Instance.h”//或其他内容。。。
实例*GetInstance()
{
静态std::unique_ptr p(新实例);
返回p.get();
}
如果编译器配置为多线程环境,那么它应该使用互斥来保护静态p,并在第一次调用初始化p时管理锁。它还应该将p销毁链接到“at_exit”链的尾部,以便在程序结束时执行适当的销毁

[编辑] 由于这是C++11的要求,并且仅在某些C++03预标准中实现,请检查编译器实现和设置


现在,我只能确保Mingw4.6已在和VS2010上运行。

不,这没有帮助。如果对
创建的
实例的写入是非原子的,则不能保证这些值对不锁定互斥锁的线程可见

e、 g.线程1调用
getInstance
created
false
,而
instance
为null,因此它会锁定互斥锁并创建一个新实例。线程1再次调用
getInstance
,这次将
created
设置为
true
。线程2现在调用
getInstance
。通过处理器内存管理的变幻莫测,它将
创建的
视为
,但不能保证它也将
实例
视为非空,即使如此,也不能保证指向的实例的内存值是一致的

如果您没有使用原子,那么您需要使用互斥体,并且必须将它们用于对受保护变量的所有访问


附加信息:如果您使用互斥锁,那么编译器和运行时将协同工作,以确保当一个线程释放互斥锁,而另一个线程获取同一互斥锁时,第二个线程可以看到第一个线程完成的所有写操作。这对于非原子访问不适用,对于原子访问也可能不适用,具体取决于编译器和运行时为您提供的内存排序约束(对于C++11原子,您可以选择排序约束)。

不,这没有帮助。如果对
创建的
实例的写入是非原子的,则不能保证这些值对不锁定互斥锁的线程可见

e、 g.线程1调用
getInstance
created
false
,而
instance
为null,因此它会锁定互斥锁并创建一个新实例。线程1再次调用
getInstance
,这次将
created
设置为
true
。线程2现在调用
getInstance
。通过处理器内存管理的变幻莫测,它将
创建的
视为
,但不能保证它也将
实例
视为非空,即使如此,也不能保证指向的实例的内存值是一致的

如果您没有使用原子,那么您需要使用互斥体,并且必须将它们用于对受保护变量的所有访问


附加信息:如果您使用互斥锁,那么编译器和运行时将协同工作,以确保当一个线程释放互斥锁,而另一个线程获取同一互斥锁时,第二个线程可以看到第一个线程完成的所有写操作。这对于非原子访问不适用,对于原子访问可能适用,也可能不适用,这取决于编译器和运行时为您提供的内存排序约束(对于C++11原子,您可以选择排序约束)。

此代码包含竞态条件,在这种情况下,可以在另一个线程同时写入创建的
时读取它

因此,它具有未定义的行为,并且不是编写代码的有效方法

正如肯尼特在评论中指出的那样,更好的选择是:

Instance* GetInstance() { static Instance instance; return &instance; }

此代码包含一个争用条件,即创建的
可以在另一个线程同时写入时读取

因此,我
static Instance *instance = 0; 

Instance *GetInstance() { 
    if (instance == NULL)  //first check.
    {
        Lock lock; //scope lock.
        if (instance == NULL) //second check, the second check must under the lock.
           instance = new Instance;
    }

    return instance;
}