C++ 什么使单线程不安全?
我在某个地方读到一个单身汉是不安全的。我想知道为什么会这样。如果我有这样一个单例对象:C++ 什么使单线程不安全?,c++,multithreading,c++11,thread-safety,singleton,C++,Multithreading,C++11,Thread Safety,Singleton,我在某个地方读到一个单身汉是不安全的。我想知道为什么会这样。如果我有这样一个单例对象: class singleton final { public: static singleton& instance() { static singleton unique; return unique; } private: singleton() = default; singleton(singleton const&
class singleton final
{
public:
static singleton& instance()
{
static singleton unique;
return unique;
}
private:
singleton() = default;
singleton(singleton const&) = delete;
singleton& operator=(singleton const&) = delete;
};
singleton *p1, *p2;
auto t1 = std::thread([] { p1 = &singleton::instance(); });
auto t2 = std::thread([] { p2 = &singleton::instance(); });
t1.join();
t2.join();
bool __instance_initialized = false;
alignas(X) char __buf_instance[sizeof(X)];
// ...
X& instance()
{
if (!__instance_initialized)
{
::new(__buf_instance) X;
__instance_initialized = true;
}
return *static_cast<X*>(__buf_instance);
}
如果我有这样的代码:
class singleton final
{
public:
static singleton& instance()
{
static singleton unique;
return unique;
}
private:
singleton() = default;
singleton(singleton const&) = delete;
singleton& operator=(singleton const&) = delete;
};
singleton *p1, *p2;
auto t1 = std::thread([] { p1 = &singleton::instance(); });
auto t2 = std::thread([] { p2 = &singleton::instance(); });
t1.join();
t2.join();
bool __instance_initialized = false;
alignas(X) char __buf_instance[sizeof(X)];
// ...
X& instance()
{
if (!__instance_initialized)
{
::new(__buf_instance) X;
__instance_initialized = true;
}
return *static_cast<X*>(__buf_instance);
}
p1
和p2
是否可能指向两个不同的singleton
实例?如果unique
是static
,那么它的“静态”性质在完全初始化之前不会生效吗?如果是这样,这是否意味着可以同时访问静态对象的初始化,从而允许创建多个静态对象?在C++98/03中,本地静态文件:
X& instance()
{
static X x;
return x;
}
这意味着您的代码将执行以下操作:
class singleton final
{
public:
static singleton& instance()
{
static singleton unique;
return unique;
}
private:
singleton() = default;
singleton(singleton const&) = delete;
singleton& operator=(singleton const&) = delete;
};
singleton *p1, *p2;
auto t1 = std::thread([] { p1 = &singleton::instance(); });
auto t2 = std::thread([] { p2 = &singleton::instance(); });
t1.join();
t2.join();
bool __instance_initialized = false;
alignas(X) char __buf_instance[sizeof(X)];
// ...
X& instance()
{
if (!__instance_initialized)
{
::new(__buf_instance) X;
__instance_initialized = true;
}
return *static_cast<X*>(__buf_instance);
}
但是现在一个线程可以将\uu instance\u initialized
设置为true并开始构造X
,并在第一个线程仍在忙于构造X
时进行第二个线程测试并跳过if
。然后,第二个线程将向其客户机提供未初始化的内存,直到第一个线程最终完成构造
在C++11中,更改了语言规则,因此编译器必须设置代码,使第二个线程不能运行过去,也不能开始构造X
,直到第一个线程成功完成构造。这可能意味着第二个线程必须等待任意时间才能继续。。。直到第一根线结束。如果第一个线程在尝试构造X
时抛出异常,那么第二个线程将醒来并尝试构造它
编译器如何完成此任务。在C++98/03中,文件本地静态:
X& instance()
{
static X x;
return x;
}
这意味着您的代码将执行以下操作:
class singleton final
{
public:
static singleton& instance()
{
static singleton unique;
return unique;
}
private:
singleton() = default;
singleton(singleton const&) = delete;
singleton& operator=(singleton const&) = delete;
};
singleton *p1, *p2;
auto t1 = std::thread([] { p1 = &singleton::instance(); });
auto t2 = std::thread([] { p2 = &singleton::instance(); });
t1.join();
t2.join();
bool __instance_initialized = false;
alignas(X) char __buf_instance[sizeof(X)];
// ...
X& instance()
{
if (!__instance_initialized)
{
::new(__buf_instance) X;
__instance_initialized = true;
}
return *static_cast<X*>(__buf_instance);
}
但是现在一个线程可以将\uu instance\u initialized
设置为true并开始构造X
,并在第一个线程仍在忙于构造X
时进行第二个线程测试并跳过if
。然后,第二个线程将向其客户机提供未初始化的内存,直到第一个线程最终完成构造
在C++11中,更改了语言规则,因此编译器必须设置代码,使第二个线程不能运行过去,也不能开始构造X
,直到第一个线程成功完成构造。这可能意味着第二个线程必须等待任意时间才能继续。。。直到第一根线结束。如果第一个线程在尝试构造X
时抛出异常,那么第二个线程将醒来并尝试构造它
编译器如何实现这一点。在C++11中,静态初始化的规则已更改为线程安全。@Jarod42我知道,但我想了解为什么它一开始不是线程安全的。仍然有一个对象,但初始化不是线程安全的:可能会返回尚未初始化的对象(对于双重初始化也不确定)单例初始化可能是线程不安全的,具体取决于它的实现方式,而单例对象本身可能是线程不安全的,具体取决于类的实现方式。如上所述,您读取的内容不正确。@Jarod42为什么不初始化它?静态初始化规则在C++11中已更改为线程安全。@Jarod42我知道,但我想了解为什么一开始它不是线程安全的。仍然有一个对象,但初始化不是线程安全的:可能会返回一个尚未初始化的对象(也不确定是否进行双重初始化)单例初始化可能是线程不安全的,具体取决于它的实现方式,而单例对象本身可能是线程不安全的,具体取决于类的实现方式。如上所述,您读到的内容是错误的。@Jarod42为什么不初始化?现在非常合理。谢谢。现在非常合理。谢谢。