g++ の -fthreadsafe-statics ってオプション知ってます?

古来より、関数スコープの静的なオブジェクトを作るのは危険

void foo() {
  static CBar bar; // こんなの

とされています。foo()が初めて呼ばれたタイミングでbarのコンストラクタが走るわけですが(C++規格でそう決まっている)、foo()の初回呼び出しが2つのスレッドでほぼ同時に行われると、barのコンストラクタが複数回走ってしまったりと、不可解な動作をすることが知られています。


ところが、最近のg++には -fthreadsafe-statics っていうオプションがあって、この初回のコンストラクタ呼びをスレッドセーフに行ってくれるようになりました。手元のgcc3.4.3ではデフォルトでonになっていました。g++ -S で上記コードのアセンブリ言語のリストを出してみて、__cxa_guard_acquire とか __cxa_guard_release という関数をcallしていたらonになっています。


これ使うと、いつぞや話題にしたシングルトンは、

template<typename T>
class MTSafeStaticSingleton : private boost::noncopyable
{
public:
  static T& getInstance(void) {
    static T instance;
    return instance;
  }
};

これだけでいいんですよね・・・。たぶん。しかも、libsupc++のソースをちゃんと読んだわけではないですけど、(メモリバリアを使用した安全な)DCLになっているのかな? 速いです。速度比較をしてみたら、こんな感じでした。自作のDCLとほぼ同じ速さ。

$ ./a.out
MTSafeStaticSingleton: 0.39 [s]    // これが今回の
DCLSingleton: 0.27 [s]
GccTSDSingleton: 0.68 [s]
OnceSingleton: 16.21 [s]
GccTsdSingleton: 22.6 [s]
SynchronizedSingleton: 43.89 [s]

でもまぁ、余計なことスンジャネーという方は -fno-threadsafe-statics でコンパイルしたほうが無難ですね。組み込み屋さんなんかは特に。時間効率的にも空間効率的にも。