Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/142.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.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
共享指针的双重检查锁定 免责声明:我来自java背景,因此,我不知道C++内部的许多内部(以及相关库)是如何工作的。_C++_Multithreading_Boost_Double Checked Locking - Fatal编程技术网

共享指针的双重检查锁定 免责声明:我来自java背景,因此,我不知道C++内部的许多内部(以及相关库)是如何工作的。

共享指针的双重检查锁定 免责声明:我来自java背景,因此,我不知道C++内部的许多内部(以及相关库)是如何工作的。,c++,multithreading,boost,double-checked-locking,C++,Multithreading,Boost,Double Checked Locking,我已经读了足够多的书,知道双重检查锁定是邪恶的,而单例模式的正确和安全实现需要适当的工具 我相信下面的代码可能是不安全的,可能会受到编译器重新排序和未初始化对象赋值的影响,但我不确定我是否遗漏了一些我不了解的语言 typedef boost::shared_ptr<A> APtr; APtr g_a; boost::mutex g_a_mutex; const APtr& A::instance() { if (!g_a) { boost::mutex::s

我已经读了足够多的书,知道双重检查锁定是邪恶的,而单例模式的正确和安全实现需要适当的工具

我相信下面的代码可能是不安全的,可能会受到编译器重新排序和未初始化对象赋值的影响,但我不确定我是否遗漏了一些我不了解的语言

typedef boost::shared_ptr<A> APtr;

APtr g_a;
boost::mutex g_a_mutex;
const APtr& A::instance()
{
  if (!g_a)
  {
    boost::mutex::scoped_lock lock(g_a_mutex);
    if (!g_a)
    {
      g_a = boost::make_shared<A>();
    }
  }

  return g_a;
}
typedef boost::shared_ptr APtr;
APtr g_a;
boost::mutex g_a_mutex;
const APtr&A::instance()
{
如果(!g_a)
{
mutex::作用域锁定锁(g_a_mutex);
如果(!g_a)
{
g_a=boost::make_shared();
}
}
返回g_a;
}
我相信实际的代码是在C++03下编译的


这个实现是否不安全?如果是这样,那么如何?

< p>这在现代C++中是绝对不必要的。对于恐龙以外的任何人来说,单例代码都应该像这样简单:

A& A::instance() {
    static A a;
    return a;
}
在C++11及更高版本中100%线程安全

然而,我必须声明:单身是邪恶的反模式,应该永远禁止

论原始代码的线程安全
是的,只要代码不安全。由于读取是在互斥锁之外完成的,因此对
g_a
本身的修改完全可能是可见的,但对对象
g_a
的修改并不指向。因此,线程将绕过互斥锁并返回指向非构造对象的指针。

是的,双重检查锁定模式在古语言中是不安全的。我做的最好的解释是:

问题显然是行分配实例——编译器可以自由地分配对象,然后将指针分配给它,或者将指针设置到要分配的位置,然后分配它


如果您使用的是C++11
std::shared_ptr
,则可以在共享指针对象上使用,这保证了它们之间以及与互斥体的正确组合;但是如果你使用的是C++11,你也可以使用一个动态初始化的
static
变量,它保证是线程安全的。

IMHO,读写不带锁是不好的:当你开始读的时候,如果有人在
g_a
里面写东西会附加什么?没有任何东西可以确保读取不会被写入
g_a
的进程中断,并在之后继续。如果(!g_a)先删除
,这将是安全的。我在别处看到过这个建议,但我不拥有有问题的代码,我只是在分析它,我相信实际的二进制文件是在C++03下编译的。我会弄清楚的。但是,我完全同意应该禁止单身人士。@afsantos,代码是不安全的。我已经解释了原因。“singleton是邪恶的反模式”规则的例外——如果返回的singleton对象是不可变的,那么就没关系了,因为如果该对象永远不可变,就不会有线程安全问题modified@JeremyFriesner首先,单例的反模式性与线程安全无关。即使在单线程应用程序中,它也是一种反模式。第二,当我们谈论单例线程安全时,我们通常指的是它的创建,而不是“底层”对象的线程安全。因此,不可变与单线程安全概念无关。@SergeyA另一种选择是让每个调用方构造并使用自己的单独(但100%相同)对象,这会使用额外的内存和CPU时间,在不可变对象的情况下没有明显的好处。关于对象创建的线程安全性,您的帖子说您的示例“在C++11及更高版本中是100%线程安全的”,所以这似乎不是问题,不仅仅是初始化代码。这可能是CPU缓存在玩把戏。这可能是编译器中的一个优化,它在执行顺序、分配到主内存等方面做了非常有趣的事情。