2

在 C++11 之前,局部静态变量不是线程安全的。我需要使用一些不可重入函数的结果来初始化性能关键函数中的静态变量。

我希望看到一个静态变量初始化,它使用互斥锁或其他同步原语,但是对常规静态变量进行一些机会性检查,以减少在很久以前已经初始化变量的典型情况下使用互斥锁。似乎 GCC 为 C++11 实现了类似的东西,如静态初始化和线程安全中所述,但那里列出的代码并不完整,只是汇编。

注意:有很多问题询问静态变量初始化是否在 Stack Overflow 上是原子的,但他们似乎对答案“否”感到满意,而且他们似乎没有显示出实际的解决方案(如C++ 静态初始化器 - 它是线程安全)。

4

2 回答 2

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)可用于只运行一次例程。这可用于以线程安全的方式初始化数据。

于 2013-09-20T08:22:09.047 回答
4

我在问题中引用的博客文章的后续文章中讨论了这一点。如果由于某种原因您不能使用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 语言标准所要求的静态块范围变量的零初始化。上述宏将让您安全地使用“魔法”静态,直到MSVC 2014提供实际的编译器和运行时支持。

于 2014-10-16T19:44:35.373 回答