如何解决用于在 C++ 中维护静态局部变量的服务数据的线程安全问题?

考虑以下场景.我们有一个带有静态局部变量的 C++ 函数:

Consider the following scenario. We have a C++ function with a static local variable:

void function()
{
    static int variable = obtain();
    //blahblablah
}

该函数需要从多个线程并发调用,所以我们添加一个临界区来避免对静态本地的并发访问:

the function needs to be called from multiple threads concurrently, so we add a critical section to avoid concurrent access to the static local:

void functionThreadSafe()
{
    CriticalSectionLockClass lock( criticalSection );
    static int variable = obtain();
    //blahblablah
}

但这足够了吗?我的意思是有一些魔法使变量被初始化不超过一次.所以运行时维护了一些服务数据,表明每个静态本地是否已经被初始化.

but will this be enough? I mean there's some magic that makes the variable being initialized no more than once. So there's some service data maintained by the runtime that indicates whether each static local has already been initialized.

上述代码中的关键部分是否也会保护该服务数据?这种情况是否需要额外的保护?

Will the critical section in the above code protect that service data as well? Is any extra protection required for this scenario?

推荐答案

C++ 说你的静态变量应该只初始化一次 - 但是 C++ 不处理线程(还).

C++ says that your static variable should only be initialized once - however C++ doesn't deal with threads(yet).

gcc(至少在 *nix 系统上)具有适当的魔法来安全地保护多个线程初始化这样的静态变量.根据 http://social.msdn.microsoft.com/Forums/en/vcgeneral/thread/12f8e2c7-d94d-4904-8c79-a0b0d1088e0b ,msvc 不会 - 在这种情况下,您必须自己锁定初始化.

gcc(atleast on *nix systems) does the proper magic to safely guard multiple threads initializing such a static variable. According to http://social.msdn.microsoft.com/Forums/en/vcgeneral/thread/12f8e2c7-d94d-4904-8c79-a0b0d1088e0b , msvc does not - and in such a case you'll have to lock the initialization yourself.

用关键部分保护初始化应该保护所有这些 - 即你的 functionThreadSafe() 是好的 - (除非 obtain() 本身调用 functionThreadSafe()

Guarding the initialization with a critical section should protect all this - i.e. your functionThreadSafe() is ok - (unless obtain() itself calls functionThreadSafe()

http://blogs.msdn.com/b/oldnewthing/archive/2004/03/08/85901.aspx 在这方面值得一读.

就个人而言,为了避免意外,我会尝试重写它,以便您可以在创建任何线程之前自己初始化 variable 一次 - 例如

Personally, to avoid surprises I'd try to rewrite this so you can initialize variable yourself, once, before you create any threads - e.g.

static int variable = 0;
void init_variable() //call this once, at the start of main()
{
  variable = obtain();
}

void function() 
{
  //use variable, lock if you write to it
}

相关文章