函数静态变量是否在GCC中是线程安全的?

CsT*_*mas 58 c++ static gcc initialization thread-safety

在示例代码中

void foo()
{
  static Bar b;
  ...
}
Run Code Online (Sandbox Code Playgroud)

使用GCC编译是否可以保证b以线程安全的方式创建和初始化?

在gcc的手册页中,找到了-fno-threadsafe-statics命令行选项:

不要发出额外的代码来使用C++ ABI中指定的例程来进行本地静态的线程安全初始化.您可以使用此选项在不需要线程安全的代码中略微减小代码大小.

  1. 这是否意味着,默认情况下,GCC的本地静态是线程安全的?所以没有理由明确保护,例如pthread_mutex_lock/unlock

  2. 如何编写可移植代码 - 如何检查编译器是否会添加其防护?或者关闭GCC的这个功能是否更好?

CB *_*ley 42

  1. 不,这意味着本地s 的初始化static是线程安全的.

  2. 您肯定希望启用此功能.本地statics的线程安全初始化非常重要.如果您通常需要线程安全访问本地statics,那么您需要自己添加适当的防护.

  • 要初始化互斥锁,您将使用它来控制对其他变量的访问. (10认同)
  • 如果必须编写可移植代码,则不能依赖函数静态的线程安全初始化.例如,MS C++没有这样做.所以我在第2点不同意 - 你可以安全地禁用它,如果你想编写可移植代码,但你不能使用函数静态,其中线程安全很重要;-) (6认同)
  • @xtofl:如果你有一个单独的单例`class singleton {static singleton&get(){static singleton s; 返回s}};`,单例必须是线程安全的这一事实与它的初始化必须是线程安全的事实正交. (4认同)
  • 如果您没有线程安全(本地函数)访问权限,那么什么是线程安全初始化? (2认同)
  • @xtofl:安全初始化意味着,例如,如果你有`static Obj o;`,那么o的构造函数只会被调用一次,即使两个线程在(几乎)同时第一次调用该函数.此外,在完成"o"的构造之前,两个线程都不能使用"o".这在概念上适用于基本类型,但对象类型使其更加明显.线程安全静态初始化并不意味着在函数体中进一步使用对象有任何同步. (2认同)

sho*_*tsy 17

我们对GCC 3.4生成的锁定代码存在严重问题,以保护本地静态初始化.该版本使用全局共享互斥锁来保护所有和任何导致代码死锁的静态初始化.我们有一个从函数结果初始化的局部静态变量,它启动了另一个线程,它创建了一个本地静态变量.伪代码:

voif f()
{
  static int someValue = complexFunction();
  ...
}
int complexFunction()
{
  start_thread( threadFunc() );
  wait_for_some_input_from_new_thread();
  return input_from_new_thread;
}
void threadFunc()
{
  static SomeClass s();
  ...
}
Run Code Online (Sandbox Code Playgroud)

唯一的解决方案是禁用gcc的这个功能.如果你需要你的代码是可移植的,那么你无论如何都不能依赖于特定gcc版本中添加的功能来保证线程安全.据说C++ 0x添加了线程安全的本地静态,直到那时这是非标准魔法,这使得你的代码不可移植,所以我建议反对它.如果您决定使用它,我建议您通过编写示例应用程序来验证您的gcc版本不会为此目的使用单个全局互斥锁.(线程安全的难度从即使是gcc也无法正确的事实中显而易见)

  • `static SomeClass s();` 是一个函数声明 (2认同)

sbi*_*sbi 6

这并不是马上回答你的问题(Charles已经这样做了),但我认为是时候再次发布这篇文章的链接了.它揭示了全局变量的初始化,并且每个尝试static在多线程环境中使用变量的人都应该阅读并理解它.


Ste*_*n C 5

我认为关键词是

... 本地静态的线程安全初始化.

我读到这意味着它只是以线程安全的方式完成静态的初始化.静态的一般使用不是线程安全的.