静态初始化不安全调用的线程安全性

时间:2016-12-23 03:10:07

标签: c++ multithreading c++11 static thread-safety

在图书馆的某个地方,我有一个看起来像 -

的功能
<h1> <br> <hr> <p>

现在您可以阅读inline int getIword() { static int i = std::ios_base::xalloc(); return i; } 来电here,但我想从提到的链接强调这一行 -

  

此功能是线程安全的;多个线程的并发访问不会导致数据竞争。 (自C ++ 14起)

它说“自C ++ 14以来”,但我也需要C ++ 11支持。由于函数调用实际上正在初始化std::ios_base::xalloc()方法的静态局部变量,并且我们知道C ++ 11代码的local static variable initialization is thread safe,因此可以安全地假设此代码是 -

  • 安全,如果只有后续的读取调用功能,例如。 getIword()

  • 安全吗?如果代码如下所示:

...

auto something = getIword()

...

如果在后面的示例中它不安全,我应该在哪里放置lock_guards以使其对C ++ 11安全?大约operator<<(std::ostream &os, T const value) { if (value == ...) { os.iword(getIword()) = 1; } else if (value == ...) { os.iword(getIword()) = 0; } return os; } 或整个方法或正在进行通话的地方?

2 个答案:

答案 0 :(得分:3)

静态局部变量初始化是线程安全的,因为如果多个线程调用该函数,那么其中只有一个实际上会初始化该变量。它不保护您初始化的东西。这意味着在这种情况下,如果你有两个不同的线程,一个调用getIword而另一个调用另一个函数同时调用std::ios_base::xalloc(),那么这两个调用将不会同步,你将有一个数据竞争,而这又是未定义的行为。

答案 1 :(得分:1)

在我的电脑上,我可以看到std::ios_base::xalloc()的实现是:

    static int __CLRCALL_OR_CDECL xalloc()
    {   // allocate new iword/pword index
    _BEGIN_LOCK(_LOCK_STREAM)   // lock thread to ensure atomicity
        return (_Index++);
    _END_LOCK()
    }

所以基本上它只是做一个增量值,没有线程安全保证你会在竞争条件下从std::ios_base::xalloc()获得一些重复值。

我将采取的解决方案是使用xalloc()编写自己的std::atomic

int xalloc()
{
    static std::atomic_int i;
    return i++;
}

使用锁定将std::ios_base::xalloc()包装到新方法。