C++ 如何以线程安全的方式避免静态数据成员初始化失败?
考虑这一点:C++ 如何以线程安全的方式避免静态数据成员初始化失败?,c++,concurrency,thread-safety,C++,Concurrency,Thread Safety,考虑这一点: class A { public: A(const char* s) { /*...*/ }; static const A& get_default() { /* avoid static data memember init fiasco */ static const A& a = A("default"); /* ..but not thread-safe */ return a; } }; 如何使g
class A {
public:
A(const char* s) { /*...*/ };
static const A& get_default() { /* avoid static data memember init fiasco */
static const A& a = A("default"); /* ..but not thread-safe */
return a;
}
};
如何使
get\u default()
线程安全?或者我如何找到一种方法来获得a::a
,避免数据成员init失败和并发。我不喜欢使用任何锁。以下内容将利用这样一个事实:调用main()
之前的初始化将在单个线程上进行,并且pInstance
指针必须在静态对象的动态初始化之前进行零初始化(3.6.2“非本地对象的初始化”)
因此,第一次调用get_default()
时,pInstance
将为空-无论该调用是否是由于A::pInstance
的初始化引起的。这将导致get_default()。需要明确的是,pInstance
的初始值设定项将强制在init线程上调用get_default()
,即使没有其他操作
对get\u default()
的后续调用不会修改pInstance
,因此它是线程安全的
请注意,更简单的是:
class A {
public:
A(const char* s) { /*...*/ };
static const A& get_default() {
static const A& a = A("default"); /* ..but not thread-safe */
return a;
}
};
namespace {
A const& trigger = A::get_default();
}
出于同样的原因,它也应该是线程安全的,但它有几个方面让我不太确定它是否会有一些潜在的缺点:
- 如果工具链确定
trigger
没有在其他地方使用(即使我们将其从匿名名称空间中删除,这也适用),我担心它可能会从程序映像中删除。我不确定该标准在防止这种优化方面会做出什么承诺——特别是如果class A
住在图书馆里
- 大概编译器只是检查一个隐藏的静态标志,以确定
get_default()
中的本地static
变量的初始化之前是否已经运行过。然而,对于使用什么机制,实际上并没有什么承诺(我还没有研究C++0x对此可能会说些什么)。在第一个示例中,init timeget\u default()
调用之后的线程安全检查就在那里-保证
以下内容将利用以下事实:调用main()
之前的初始化将在单个线程上进行,并且pInstance
指针必须在静态对象的动态初始化之前进行零初始化(3.6.2“非本地对象的初始化”)
因此,第一次调用get_default()
时,pInstance
将为空-无论该调用是否是由于A::pInstance
的初始化引起的。这将导致get_default()。需要明确的是,pInstance
的初始值设定项将强制在init线程上调用get_default()
,即使没有其他操作
对get\u default()
的后续调用不会修改pInstance
,因此它是线程安全的
请注意,更简单的是:
class A {
public:
A(const char* s) { /*...*/ };
static const A& get_default() {
static const A& a = A("default"); /* ..but not thread-safe */
return a;
}
};
namespace {
A const& trigger = A::get_default();
}
出于同样的原因,它也应该是线程安全的,但它有几个方面让我不太确定它是否会有一些潜在的缺点:
- 如果工具链确定
trigger
没有在其他地方使用(即使我们将其从匿名名称空间中删除,这也适用),我担心它可能会从程序映像中删除。我不确定该标准在防止这种优化方面会做出什么承诺——特别是如果class A
住在图书馆里
- 大概编译器只是检查一个隐藏的静态标志,以确定
get_default()
中的本地static
变量的初始化之前是否已经运行过。然而,对于使用什么机制,实际上并没有什么承诺(我还没有研究C++0x对此可能会说些什么)。在第一个示例中,init timeget\u default()
调用之后的线程安全检查就在那里-保证
FWIW,这在C++0x中已经是完全线程安全的。在C++0x中可能是这样的(您可以发布一个链接)。但是c++0x还不是标准的。这不是静态初始化顺序的失败@太空:的确。但是OP的代码片段是避免它的一种方法。但它在多线程上下文中有问题。请参阅:FWIW,这在C++0x中已经是完全线程安全的。在C++0x中可能是这样(您可以发布一个链接)。但是c++0x还不是标准的。这不是静态初始化顺序的失败@太空:的确。但是OP的代码片段是避免它的一种方法。但它在多线程上下文中有问题。请参阅:谢谢Michael。这就是我一直在寻找的解决方案!谢谢你,迈克尔。这就是我一直在寻找的解决方案!