g++ の -fthreadsafe-statics ってオプション知ってます?
古来より、関数スコープの静的なオブジェクトを作るのは危険
void foo() { static CBar bar; // こんなの
とされています。foo()が初めて呼ばれたタイミングでbarのコンストラクタが走るわけですが(C++規格でそう決まっている)、foo()の初回呼び出しが2つのスレッドでほぼ同時に行われると、barのコンストラクタが複数回走ってしまったりと、不可解な動作をすることが知られています。
- 参考サイト: http://blogs.msdn.com/oldnewthing/archive/2004/03/08/85901.aspx (引用するの何度目だろ)
ところが、最近の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 でコンパイルしたほうが無難ですね。組み込み屋さんなんかは特に。時間効率的にも空間効率的にも。