C++ 如何在C++;03?
在C++11之前,局部静态变量不是线程安全的。我需要在一个性能关键函数中初始化一个静态变量,其结果是某个不可重入函数 我希望看到一个静态变量初始化,它使用互斥体或其他同步原语,但对常规静态变量进行一些机会主义检查,以减少互斥体在典型情况下的使用,因为该变量很久以前就已经初始化了。如中所述,GCC似乎为C++11实现了类似的功能,但此处列出的代码并不完整,只是汇编代码C++ 如何在C++;03?,c++,multithreading,static,initialization,c++03,C++,Multithreading,Static,Initialization,C++03,在C++11之前,局部静态变量不是线程安全的。我需要在一个性能关键函数中初始化一个静态变量,其结果是某个不可重入函数 我希望看到一个静态变量初始化,它使用互斥体或其他同步原语,但对常规静态变量进行一些机会主义检查,以减少互斥体在典型情况下的使用,因为该变量很久以前就已经初始化了。如中所述,GCC似乎为C++11实现了类似的功能,但此处列出的代码并不完整,只是汇编代码 注意:有很多问题询问静态变量初始化是否是堆栈上的原子溢出,但他们似乎满足于回答“否”,并且似乎没有显示实际的解决方案(如)。您可以
注意:有很多问题询问静态变量初始化是否是堆栈上的原子溢出,但他们似乎满足于回答“否”,并且似乎没有显示实际的解决方案(如)。您可以将静态数据放入函数中并利用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;
}
数据将在第一次函数调用时进行静态初始化,然后调用一次 在: call_once函数和once_标志类型 (静态初始化为BOOST_ONCE_INIT)可用于运行 例行公事就一次。这可用于初始化数据库中的数据 线程安全方式 我在问题中引用的博客文章的一篇文章中讨论了这一点。如果由于某种原因您不能使用
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语言标准所要求的。上述宏将允许您安全地使用“神奇”静态,直到实际的编译器和运行时支持到达。在C++03中没有可移植的解决方案,因为在C++03中没有线程的概念。您必须向操作系统寻求帮助。我不知道你的操作系统,所以我帮不了你。@knivil我正在寻找一个实用的解决方案,不一定是便携式的(但隔离非便携式部分会很方便)。假设我有一个可移植的互斥体(这听起来很合理,因为几乎所有平台都有某种互斥体),线程安全解决方案会是什么样子呢?如果您不想使用boost,那么针对POSIX和….使用pthread_一次。。。。(?)用于windows。我试图自己编写一个基于互斥的实现,但很快意识到它比看起来更复杂。问题是互斥对象本身在初始化之前无法使用,它的初始化需要是线程安全的,或者在调用函数之前完成。这可能就是GCC最初选择全局互斥的原因。我可能会检查最近的GCC是如何解决这个问题的(或者boost或std call_是如何实现的)。我假设这将确保初始化不会被调用两次,但它是否也确保“数据”在访问时已经初始化?数据将在第一次函数调用时静态初始化,然后调用一次。说“在上述所选函数的执行成功完成之前,组中没有调用返回”,这是我正在寻找的保证,但我在中没有看到。即使它有效,我还是更喜欢一个没有增压的解决方案。我认为模仿boost::用互斥器调用_一次应该是可能的?@Suma:如果我是你,我会选择boost。它保证是正确的,并且可能是编译器上可用的最快的实现——不管这是什么。而且它是便携式的。一旦编译器支持,就可以直接将其切换到std::call_。但是是的,它可以通过互斥来完成。