简体   繁体   English

如何在C ++ 03中实现线程安全的本地静态变量?

[英]How to implement thread safe local static variable in C++03?

Before C++11 local static variables were not thread safe. 在C ++ 11之前,本地静态变量不是线程安全的。 I need to initialize a static variable in a performance critical function with a result of some non-reentrant function. 我需要在性能关键函数中初始化一个静态变量,其结果是一些非重入函数。

I would like to see a static variable initialization which uses mutexes or other synchronization primitives, but has some opportunistic check of a regular static variable to reduce the mutex use in a typical situation when the variable has already been initialized a long ago. 我希望看到一个静态变量初始化,它使用互斥锁或其他同步原语,但对常规静态变量进行一些机会检查,以便在很久以前已经初始化变量的典型情况下减少互斥量的使用。 It seems GCC implements something like this for C++11, as mentioned in Static initialization and thread safety , but the code listed there is not complete and is assembly only. 似乎GCC为C ++ 11实现了类似的东西,如静态初始化和线程安全中所提到的,但是那里列出的代码并不完整,只是汇编。

Note: There is plenty of questions asking IF the static variable initialization is atomic on Stack Overflow, but they seem to be content with the answer "no" and they do not seems to show a practical solution (like C++ Static Initializer - Is it thread safe ). 注意:有很多问题要求如果静态变量初始化在Stack Overflow上是原子的,但它们似乎满足于答案“否”并且它们似乎没有显示实际的解决方案(如C ++静态初始化程序 - 它是否是线程安全 )。

You could put the static data in a function and utilize boost::once: 您可以将静态数据放在函数中并使用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;
}

The data will be static initialized at first function call, after that the call once is done. 数据将在第一次函数调用时初始化,之后调用一次。

In http://www.boost.org/doc/libs/1_32_0/doc/html/call_once.html : http://www.boost.org/doc/libs/1_32_0/doc/html/call_once.html中

The call_once function and once_flag type (statically initialized to BOOST_ONCE_INIT) can be used to run a routine exactly once. call_once函数和once_flag类型(静态初始化为BOOST_ONCE_INIT)可用于仅运行一次例程。 This can be used to initialize data in a thread-safe manner. 这可用于以线程安全的方式初始化数据。

I discussed this in a follow-up to the blog post referenced in the question. 我在对问题中引用的博客文章的后续内容中进行了讨论。 If for some reason you can't use boost::call_once your block-scoped static is a pointer, POD, or has a thread-safe constructor, you can write the same initialization guard code that GCC would emit: 如果由于某种原因你不能使用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)

You can use this like 你可以像这样使用它

void concurrently_accessed() {
    STATIC_DEFINE_ONCE(int, local_var, thread_unsafe_initializer());
    // ...
}

This approach takes advantage of zero-initialization of static block-scoped variables, which is required by the C language standard. 这种方法利用了静态块范围变量的零初始化,这是C语言标准所要求的。 The above macros will let you safely use "magic" statics until actual compiler & run-time support arrive in MSVC 2014 . 上述宏将让您安全地使用“魔术”静态,直到实际的编译器和运行时支持到达MSVC 2014

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM