在C ++ 11之前,本地静态变量不是线程安全的。我需要在一个性能关键函数中初始化一个静态变量,其结果是一些非重入函数。
我希望看到一个使用互斥锁或其他同步原语的静态变量初始化,但是在很久以前已经初始化变量的情况下,对常规静态变量进行机会检查以减少常规情况下的互斥使用。似乎GCC为{+ 3}}中提到的C ++ 11实现了类似的东西,但是那里列出的代码并不完整,只是汇编。
注意:有很多问题要求静态变量初始化在Stack Overflow上是原子的,但它们似乎满足于答案" no"它们似乎没有显示出实际的解决方案(如Static initialization and thread safety)。
答案 0 :(得分:4)
您可以将静态数据放在函数中并使用boost :: once:
int& get_static() {
static boost::once_flag once_flag = BOOST_ONCE_INIT;
static int* data;
struct Initialize
{
static void apply() {
data = new int(1);
}
};
boost::call_once(once_flag, &Initialize::apply);
return *data;
}
数据将在第一次函数调用时初始化,之后调用一次。
在http://www.boost.org/doc/libs/1_32_0/doc/html/call_once.html中:
call_once函数和once_flag类型 (静态初始化为BOOST_ONCE_INIT)可用于运行a 例程一次。这可用于初始化a中的数据 线程安全的方式。
答案 1 :(得分:4)
我在follow-up中对问题中引用的博客文章进行了讨论。如果由于某种原因你不能使用boost::call_once
你的块范围的静态是一个指针,POD,或者有一个线程安全的构造函数,你可以编写GCC会发出的相同的初始化保护代码:
// Define a static local variable once, safely, for MSVC
//
// This macro is necessary because MSVC pre-2013 doesn't
// properly implement C++11 static local initialization.
// It is equivalent to writing something like
//
// static type var = stmt;
//
// in a compliant compiler (e.g. GCC since who knows when)
// States for lock checking
enum { uninitialized = 0, initializing, initialized };
// Preprocessor hackery for anonymous variables
#define PASTE_IMPL(x, y) x ## y
#define PASTE(x, y) PASTE_IMPL(x, y)
#define ANON_VAR(var) PASTE(var, __LINE__)
#define STATIC_DEFINE_ONCE(type, var, stmt) \
static type var; \
static int ANON_VAR(state); \
bool ANON_VAR(cont) = true; \
while (ANON_VAR(cont)) { \
switch (InterlockedCompareExchange(&ANON_VAR(state), \
initializing, uninitialized)) { \
case uninitialized: \
var = stmt; \
InterlockedExchange(&ANON_VAR(state), initialized); \
ANON_VAR(cont) = false; \
break; \
case initializing: \
continue; \
case initialized: \
ANON_VAR(cont) = false; \
break; \
} \
} do { } while (0)
你可以像
一样使用它void concurrently_accessed() {
STATIC_DEFINE_ONCE(int, local_var, thread_unsafe_initializer());
// ...
}
这种方法利用了静态块范围变量的零初始化,这是C语言标准所要求的。以上宏将让您安全地使用" magic"静态直到实际的编译器和运行时支持到达MSVC 2014。