C++ 如何在C++;03?

C++ 如何在C++;03?,c++,multithreading,static,initialization,c++03,C++,Multithreading,Static,Initialization,C++03,在C++11之前,局部静态变量不是线程安全的。我需要在一个性能关键函数中初始化一个静态变量,其结果是某个不可重入函数 我希望看到一个静态变量初始化,它使用互斥体或其他同步原语,但对常规静态变量进行一些机会主义检查,以减少互斥体在典型情况下的使用,因为该变量很久以前就已经初始化了。如中所述,GCC似乎为C++11实现了类似的功能,但此处列出的代码并不完整,只是汇编代码 注意:有很多问题询问静态变量初始化是否是堆栈上的原子溢出,但他们似乎满足于回答“否”,并且似乎没有显示实际的解决方案(如)。您可以

在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_。但是是的,它可以通过互斥来完成。