[C++] GCC中的函數靜態變量是否是線程安全的?


Answers

我們對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();
  ...
}

唯一的解決辦法是禁用gcc的這個功能。 如果你需要你的代碼是可移植的,我們所做的,你不能依賴於特定的gcc版本中添加的功能來保證線程安全。 據說C ++ 0x增加了線程安全的本地靜態,直到這是非標準的魔法,這使得你的代碼不可移植,所以我建議反對它。 如果您決定使用它,我建議您通過編寫示例應用程序驗證您的gcc版本不使用單個全局互斥體來實現此目的。 (線程安全的困難從甚至gcc不能正確的事實中是顯而易見的)

Question

在示例代碼中

void foo()
{
  static Bar b;
  ...
}

GCC編譯是保證b將被創建並以線程安全的方式初始化?

在gcc的手冊頁中,找到了-fno-threadsafe-statics命令行選項:

不要發出額外的代碼來使用C ++ ABI中指定的例程來進行本地靜態的線程安全初始化。 您可以使用此選項在不需要線程安全的代碼中稍微減少代碼大小。

  1. 這是否意味著,本地靜態在GCC默認情況下是線程安全的? 那麼沒有理由明確地捍衛,例如與pthread_mutex_lock/unlock

  2. 如何編寫可移植代碼 - 如何檢查編譯器是否會添加其警衛? 還是關閉GCC的這個功能更好?




我認為關鍵在於

本地靜態線程安全初始化

我讀這意味著它只是一個線程安全的靜態初始化。 靜態的一般使用不會是線程安全的。