web-dev-qa-db-ja.com

関数静的変数はGCCでスレッドセーフですか?

サンプルコードでは

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

[〜#〜] gcc [〜#〜]でコンパイルすると、bがスレッドセーフな方法で作成および初期化されることが保証されますか?

Gccのmanページで、-fno-threadsafe-staticsコマンドラインオプションを見つけました。

ローカル静的変数のスレッドセーフな初期化のためにC++ ABIで指定されたルーチンを使用するための追加コードを発行しないでください。このオプションを使用すると、スレッドセーフである必要がないコードでコードサイズをわずかに減らすことができます。

  1. これは、GCCではデフォルトでローカル統計がスレッドセーフであることを意味しますか?したがって、明示的に保護する理由はありません。 pthread_mutex_lock/unlock

  2. 移植可能なコードの書き方-コンパイラがガードを追加するかどうかを確認する方法は?それとも、GCCのこの機能をオフにした方が良いですか?

58
CsTamas
  1. いいえ、それはローカルstaticsの初期化がスレッドセーフであることを意味します。

  2. この機能を有効にしたままにする必要があります。ローカルstaticsのスレッドセーフな初期化は非常に重要です。ローカルstaticsへのスレッドセーフなアクセスが一般的に必要な場合は、適切なガードを自分で追加する必要があります。

42
CB Bailey

ローカルの静的初期化を保護するために、GCC 3.4によって生成されたロックコードに重大な問題がありました。そのバージョンではglobal shared mutexを使用して、コードでデッドロックを引き起こすすべての静的な初期化を保護しています。ローカル静的変数を作成した別のスレッドを開始した関数の結果から初期化されたローカル静的変数がありました。疑似コード:

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バージョンがこの目的で単一のグローバルmutexを使用していないことを確認することをお勧めします。 (スレッドセーフの難しさは、gccでも正しく理解できないことから明らかです)

17
shojtsy

これはあなたの質問にすぐには答えていません( チャールズはすでにそれをしました )が、もう一度 この記事 へのリンクを投稿する時がきたと思います。それはグローバルの初期化に光を投げ、マルチスレッド環境でstatic変数を使用しようとするすべての人が読んで理解する必要があります。

6
sbi

キーフレーズは

...スレッドセーフ--​​初期化ローカル静的。

私はこれを、スレッドセーフな方法で行われるのはstaticの初期化のみであることを意味すると読みました。 staticの一般的な使用はスレッドセーフではありません。

5
Stephen C