【发布时间】:2018-09-01 12:53:59
【问题描述】:
当必须使用 C++11 实现线程安全单例时,我知道的唯一正确实现如下:
// header
class Singleton final {
public:
static Singleton& getInstance();
private:
Singleton() = default;
Singleton(Singleton const&) = delete;
void operator=(Singleton const&) = delete;
};
// implementation:
Singleton& Singleton::getInstance() {
static Singleton instance;
return instance;
}
A. Williams 在他的《C++ Concurrency in Action》一书中写道,自 C++11 以来,“初始化被定义为恰好发生在一个线程上”,因此“可以用作 std::call_once 的替代方案”当需要单个全局实例时。当像上面定义的那样调用单例的析构函数时,我会感到很痛苦。
标准 (ISO/IEC 14882:2011) 定义为 §3.6.3 e 的一部分。 g.
已初始化对象的析构函数(即,其 生命周期已开始)具有静态存储持续时间的称为 从 main 返回的结果和调用 std::exit 的结果。
和
调用在 cstdlib 中声明的函数 std::abort() 会终止 程序不执行任何析构函数并且不调用 传递给 std::atexit() 或 std::at_quick_exit() 的函数。
那么在干净的退出(从 main 返回)首先会发生什么?是否所有线程都在“调用具有静态存储持续时间的初始化对象”的析构函数之前或之后停止?
我知道使用由共享库提供的单例是一个坏主意(它可能在其他可能使用它的部分之前被卸载)。 当 Singleton::getInstance() 被调用时会发生什么。 G。来自其他(分离的)线程?这会导致未定义的行为还是所有线程 (分离与否)在调用静态变量的析构函数之前被终止/加入?
(明确一点:我认为单例是一种反模式,但是当我必须使用它时,我想知道会发生什么样的坏事。)
【问题讨论】:
-
我不明白这个问题,对不起。您引用了告诉您何时调用析构函数的文本。如果您想具体了解分离线程,那么您可能会对this answer 感兴趣。
-
Quoting: "静态 存储时长。对象的存储在程序开始时分配,在程序结束时释放。对象的实例只存在一个。在命名空间范围内声明的所有对象(包括全局命名空间)都具有此存储持续时间,以及使用
static或extern声明的对象。”也看看thread_local。 -
我相信静态破坏的发生顺序与构造相反。这应该意味着单例是在 任何绑定到它的引用之前创建的。我怀疑只有当有人拿到它的地址并使用它而不是引用时才会有问题。但我不是 100% 肯定是这样......
-
我不认为这完全是重复的,但答案可能埋在这里stackoverflow.com/questions/1008019/c-singleton-design-pattern
-
我认为您不能在 Singleton 类之外调用
Singleton::getInstance方法,因为它不是静态的,并且您无法创建Singleton的实例,因为您将构造函数声明为私有。您应该将Singleton::getInstance设为静态。
标签: c++ multithreading c++11