Oracle Solaris Studio 12.2: スレッドアナライザユーザーズガイド

2.6.3 二重検査されたロックを使用したプログラム

シングルトンは、特定の種類のオブジェクトが、プログラム全体で 1 つしか存在しないようにします。二重検査されたロックは、マルチスレッドアプリケーションでシングルトンを初期化する一般的で効率的な方法です。次のコードは、この実装方法を示します。

 100 class Singleton {
 101     public:
 102     static Singleton* instance();
 103     ...
 104     private:
 105     static Singleton* ptr_instance;
 106 };
 ...

 200 Singleton* Singleton::ptr_instance = 0;
 ...

 300 Singleton* Singleton::instance() {
 301     Singleton *tmp = ptr_instance;
 302     memory_barrier();
 303     if (tmp == NULL) {
 304         Lock();
 305         if (ptr_instance == NULL) {
 306             tmp = new Singleton;
 307             memory_barrier();
 308             ptr_instance = tmp;
 309         }
 310         Unlock();
 311     }
 312     return tmp;
 313 }

ptr_instance の読み取り (行 301) は、ロックによって意図的に保護されていません。このため、マルチスレッド環境でシングルトンがすでにインスタンス化されているかどうかを判別するチェックが効率的になります。変数 ptr_instance の行 301 での読み取りと行 308 での書き込みとの間でデータの競合があるが、プログラムは正しく動作することに注意してください。ただし、データの競合を許可する正しいプログラムを作成すると、余分な注意が必要になります。たとえば、前述の二重検査されたロックコードでは、シングルトンおよび ptr_instance を適切な順序で設定および読み取りできるように、行 302 および 307 での memory_barrier() の呼び出しが使用されます。この結果、すべてのスレッドは連続してこれらを読み取ります。このプログラムテクニックは、メモリーバリアーを使用しない場合には機能しません。