C ++ 11では、ローカル静的変数の初期化はスレッドセーフですか?

これはしばしば尋ねられる質問ですが、非常に多くの亜種があるので、私はそれを再述べたいと思います。何かのようなもの

Logger& g_logger() {
    static Logger lg;
    return lg;
}

変数lgのコンストラクタは一度だけ実行することが保証されていますか?

私は以前の答えから、C ++ 03ではこれがそうではないことを知っています。 C ++ 0xドラフトでは、これが強制されます。しかし、私はより明確な答えを望んでいます

  1. C ++ 11標準(ドラフトではない)では、スレッドセーフな初期化動作が終了しましたか?
  2. 上記がyesの場合、最新のgcc 4.7、vc 2011、clang 3.0の最新のリリースでは、それらが正しく実装されていますか?
179
追加された 編集された
ビュー: 1
他のスレッドが実行される前にg_loggerがmain()から一度呼び出されることを保証すれば、VS2013では安全ですか?
追加された 著者 paulm,
Visual Studio 2012 Update 3はそれをサポートしていません - 私は短いテストプログラムでテストし、アセンブリコードを見ました。
追加された 著者 Tobias Langner,
そのような機能の目的を尋ねることはできますか?単純なグローバルな Logger g_logger; に比べてどのような利点がありますか?
追加された 著者 Chris Lutz,
@balki、GCCはこれを10年近く実装しています。 Clangもそれをサポートしています。
追加された 著者 Jonathan Wakely,
@Chris:確定的な初期化と静的な初期化順序の失敗の回避。関数が最初に呼び出されると、ローカル統計は最初に初期化されます。
追加された 著者 Xeo,
2番目の質問では、まだコンパイラがこれを実装していません。
追加された 著者 balki,
VS 2015には「魔法の静的統計」が最終的に来ています。 blogs.msdn.com/b/vcblog/archive/2014/11/17/…
追加された 著者 mlvljr,
ありがとうゼオ、それが主な理由です。 1.通常、ロギングシステムでは、クライアントコードはLOG << "your log" ...のようにマクロとして使用し、マクロにはロガーへの決定的なアクセス権が必要です。2.ロガーは作成されませんあなたがそれを使用しないならば。 3.クライアントに複数のロガーを作成させたくない場合(同期の問題などがあります)、ロガーには専用のコンストラクターがあり、これは友人のg_logger()によってのみアクセス可能です。
追加された 著者 Ralph Zhang,
また、Visual Studio 2013も表示されます。 msdn.microsoft.com/en-us/library/vstudio/…
追加された 著者 rkjnsn,

2 答え

関連するセクション6.7:

このような変数は、コントロールが宣言を最初に通過するときに初期化されます。そのような変数は、その初期化の完了時に初期化されたものと見なされます。 [...]変数が初期化されている間にコントロールが同時に宣言に入ると、並行実行は初期化の完了を待たなければなりません。

次に脚注があります:

実装では、イニシャライザの実行にデッドロックが発生してはなりません。

そう、あなたは安全です。

(これは、参照を介した変数へのその後のアクセスについては何も言及していません)。

160
追加された
Logger のデフォルトのコンストラクタがスレッドセーフである場合、つまり変更可能な共有リソースにアクセスしない場合にのみ、 static Logger 内部的には、グローバル変数やシングルトンを通じて言います。標準では、これはのみであることに注意してください。一つのスレッドが同時にコンストラクタの実行を開始しようとすると、そのうちの一つだけが実際に実行され、初期化の完了のために。しかし、この規格は、コンストラクター自体のスレッド安全性を保証するものではありません。
追加された 著者 Nawaz,
@KerrekSB:私はそれが意味するものについても説明しました:つまり、内部的に変更可能な共有リソースにアクセスしません。ただ1つのスレッドだけがコンストラクタを実行するため、必ずしもスレッドセーフであるとは限りません。保護されていない共有リソースを変更すると、スレッドセーフではありません。
追加された 著者 Nawaz,
@ Nawaz:コンストラクタはスレッドセーフでなければならないのですか?一つのスレッドだけがコンストラクタを実行すると言った。
追加された 著者 Kerrek SB,
@Nawaz:まあ、それは本当ですが、それも完全な一般性です:共有データの同時アクセスは同期しなければなりません。私は、静的初期設定が何とかそのルールからの免除を提供するという提案はないと思うので、私はそれを特に呼び出す価値があるとは思わなかった。
追加された 著者 Kerrek SB,
この質問や答えに「Meyers Singleton」というフレーズは言及されていないが、
追加された 著者 Nemo,
また、変数の読者については何も言いません。つまり、静的コンストラクタの前にリーダがない場合は、TSANの問題が発生する可能性があります。もちろん、上記のパターン(fooとGetFooLog(){static foo bar; return bar;}を使用すると、TSANの問題は発生しません。
追加された 著者 jesup,
追加された 著者 Ion Todirel,

--fno-threadsafe-staticsも言及する価値があります。 gccの場合:

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

Also, have a look at the old thread Are function static variables thread-safe in GCC?

9
追加された