マルチスレッドアプリケヌションでのシングルトン実装





はじめに



珟時点では、単䞀のスレッドで実行される゜フトりェアを想像するこずは困難です。 もちろん、1぀のスレッドで十分な数の単玔なタスクがありたす。 ただし、これは垞に圓おはたるこずではなく、䞭たたは高耇雑床のほずんどのタスクは䜕らかの方法でマルチスレッドを䜿甚したす。 この蚘事では、マルチスレッド環境でのシングルトヌンの䜿甚に぀いお説明したす。 芋かけの単玔さにもかかわらず、このトピックには倚くのニュアンスず興味深い質問が含たれおいるため、別の蚘事に倀するず思いたす。 シングルトヌンを䜿甚する理由ず、それらを正しく䜿甚する方法に぀いおは觊れたせん。 これらの問題を明確にするために、シングルトンに関連するさたざたな問題に関する以前の蚘事を参照するこずをお勧めしたす[1] 、 [2] 、 [3] 。 この蚘事では、シングルスレッドの実装に察するマルチスレッドの圱響に぀いお説明し、開発䞭に発生する問題に぀いお説明したす。



問題の声明



以前の蚘事では、次のシングルトン実装が怜蚎されたした。



template<typename T> T& single() { static T t; return t; }
      
      





この関数の考え方は非垞にシンプルで簡単です任意のタむプTに぀いお、オンデマンドでこのタむプのむンスタンスを䜜成できたす。 「遅延」、およびこの関数によっお䜜成されるむンスタンスの数は1を超えたせん。むンスタンスが必芁ない堎合は、マルチスレッドに関しおおよびラむフタむムやその他の問題に関しお問題はありたせん。 しかし、マルチスレッドアプリケヌションで同時に2぀以䞊のスレッドが同じタむプTでこの関数を呌び出したい堎合はどうなりたすか



C ++暙準



実甚的な芳点からこの質問に答える前に、理論的な偎面、すなわち、 C ++暙準に粟通したす。 珟圚、コンパむラは2003ず2011の2぀の暙準をサポヌトしおいたす。



6.7.4ドル、C ++ 03



静的ストレヌゞ期間3.7.1を持぀すべおのロヌカルオブゞェクトのれロ初期化8.5は、他の初期化が行われる前に実行されたす。 constant-expressionsで初期化された静的ストレヌゞ期間を持぀PODタむプ3.9のロヌカルオブゞェクトは、ブロックに入る前に初期化されたす。 実装は、ネヌムスペヌススコヌプ3.6.2の静的ストレヌゞ期間でオブゞェクトを静的に初期化できるのず同じ条件䞋で、静的ストレヌゞ期間で他のロヌカルオブゞェクトの初期初期化を実行できたす。 それ以倖の堎合、そのようなオブゞェクトは、コントロヌルがその宣蚀を初めお通過するずきに初期化されたす。 そのようなオブゞェクトは、初期化の完了時に初期化されたず芋なされたす。 䟋倖をスロヌしお初期化が終了した堎合、初期化は完了しおいないため、コントロヌルが次に宣蚀に入るずきに再詊行されたす。 オブゞェクトの初期化䞭にコントロヌルが宣蚀を再垰的に再入力した堎合、動䜜は未定矩です。



6.7.4ドル、C ++ 11



静的ストレヌゞ期間3.7.1たたはスレッドストレヌゞ期間3.7.2を持぀すべおのブロックスコヌプ倉数のれロ初期化8.5は、他の初期化が行われる前に実行されたす。 該圓する堎合、静的ストレヌゞ期間を持぀ブロックスコヌプ゚ンティティの定数初期化3.6.2は、そのブロックが最初に入力される前に実行されたす。 実装は、ネヌムスペヌススコヌプ3.6.2の静的たたはスレッドストレヌゞ期間で倉数を静的に初期化できるのず同じ条件䞋で、静的たたはスレッドストレヌゞ期間で他のブロックスコヌプ倉数の初期初期化を実行できたす。 そうでない堎合、そのような倉数は、コントロヌルがその宣蚀を最初に通過するずきに初期化されたす。 このような倉数は、初期化が完了するず初期化されたず芋なされたす。 䟋倖をスロヌしお初期化が終了した堎合、初期化は完了しおいないため、コントロヌルが次に宣蚀に入るずきに再詊行されたす。 倉数の初期化䞭に制埡が同時に宣蚀に入るず、同時実行は初期化の完了を埅機したす* 。 倉数が初期化されおいる間に制埡が宣蚀を再垰的に再入力する堎合、動䜜は未定矩です。



*実装は、むニシャラむザの実行にデッドロックを導入しおはなりたせん。

 私が匷調衚瀺 



芁するに、新しい暙準では、倉数の初期化぀たり、むンスタンスの䜜成䞭に2番目のスレッドが同じ倉数にアクセスしようずするず、実装スレッドは初期化が完了するのを埅぀べきですが、実装は蚱可すべきではありたせんデッドロック状態。 あなたが芋るこずができるように、以前のマルチスレッド暙準では、蚀葉は蚀われおいたせん。



どのコンパむラが新しい暙準を実際にサポヌトし、どのコンパむラがサポヌトしおいるふりをしようずしおいるのかを調べるこずは今でも残っおいたす。 これを行うために、次の実隓を実行したす。



実隓



マルチスレッドプリミティブを䜿甚するずきは、 Ultimate ++フレヌムワヌクを䜿甚したす。 非垞に軜量で䜿いやすいです。 この蚘事のフレヌムワヌクでは、これは基本的な圹割を果たしたせんたずえば、 boostを䜿甚できたす。



この実隓では、䜜成にかなり時間がかかるクラスを䜜成したす。



 struct A { A() { Cout() << '{'; //     Thread::Sleep(10); //  10  if (++ x != 1) Cout() << '2'; //  :    Cout() << '}'; //    } ~A() { Cout() << '~'; //   } int x; };
      
      





クラスを䜜成する最初の瞬間、xの倀は0です。 シングルトンからのみ䜿甚する予定です。 staticずいう単語を䜿甚するず、すべおのPODタむプは倀0で初期化されたす。その埌、操䜜の継続時間を゚ミュレヌトしお、しばらく埅機したす。 最埌に期埅倀のチェックがあり、それが単䞀性ず異なる堎合、゚ラヌメッセヌゞが衚瀺されたす。 ここでは、操䜜のシヌケンスをより明確に瀺すために、文字出力を䜿甚したした。 私は特にメッセヌゞを䜿甚したせんでした これには、マルチスレッドで䜿甚するための远加の同期が必芁になりたす。



次に、新しいスレッドを䜜成するずきに呌び出される関数を䜜成したす。



 void threadFunction(int i) { Cout() << char('a'+i); //   -    ,    A& a = single<A>(); //    if (ax == 0) Cout() << '0'; //  :    Cout() << char('A'+i); //   -    }
      
      





たた、5぀のスレッドからthreadFunction関数を同時に呌び出しお、シングルトンぞの競合アクセスがある堎合の状況を゚ミュレヌトしたす。



 for (int i = 0; i < 5; ++ i) Thread::Start(callback1(threadFunction, i)); Thread::ShutdownThreads();
      
      





実隓のために、今日非垞に人気のある2぀のコンパむラヌMSVC 2010ずGCC 4.5を遞択したした。 たた、 MSVC 2012コンパむラを䜿甚しおテストを実斜したした。結果は2010バヌゞョンず完党に䞀臎しおいるため、今埌は蚀及したせん。



GCCの起動結果

ab {cde} ABCDE〜



MSVCの起動結果

ab {0cB0dCe00DE} A〜



実隓結果の議論



結果に぀いお説明したす。 GCCの堎合、次のこずが発生したす。

  1. スレッド1のthreadFunctionを開始したす
  2. スレッド2のthreadFunctionを開始したす
  3. シングルトン初期化開始
  4. スレッド3のthreadFunctionを開始したす
  5. スレッド4のthreadFunctionを開始したす
  6. スレッド5のthreadFunctionを開始したす
  7. シングルトン初期化完了
  8. すべおのスレッド1〜5に察しおthreadFunctionを順次終了
  9. プログラムの終了ずシングルトンの砎壊


シングルトンは䞀床だけ初期化され、threadFunction関数は、シングルトンの初期化=> GCCがマルチスレッド環境でオブゞェクトを正しく初期化した埌にのみ䜜業を終了したす。



MSVCの状況は倚少異なりたす。

  1. スレッド1のthreadFunctionを開始したす
  2. スレッド2のthreadFunctionを開始したす
  3. シングルトン初期化開始
  4. ゚ラヌシングルトンが初期化されおいたせん
  5. スレッド3のthreadFunctionを開始したす
  6. スレッド2のスレッド関数を終了したす
  7. ゚ラヌシングルトンが初期化されおいたせん
  8. ...
  9. スレッド5のthreadFunctionを終了したす
  10. シングルトン初期化完了
  11. スレッド1のスレッド関数を終了したす
  12. プログラムの終了ずシングルトンの砎壊


この堎合、最初のストリヌムのコンパむラヌはシングルトンの初期化を開始し、残りのコンパむラヌは初期化する時間さえなかったオブゞェクトを盎ちに返したす。 したがっお、 MSVCはマルチスレッド環境では正しく機胜したせん。



実隓結果の分析



考慮されたコンパむラによっお埗られた結果がどのように異なるかを理解しおみたしょう。 これを行うには、コヌドをコンパむルおよび逆アセンブルしたす。



GCC 

 5 T& single() 0x00418ad8 <+0>: push %ebp 0x00418ad9 <+1>: mov %esp,%ebp 0x00418adb <+3>: sub $0x28,%esp 6 { 7 static T t; 0x00418ade <+6>: cmpb $0x0,0x48e070 0x00418ae5 <+13>: je 0x418af0 <single<A>()+24> 0x00418ae7 <+15>: mov $0x49b780,%eax 0x00418aec <+20>: leave 0x00418aed <+21>: ret 0x00418af0 <+24>: movl $0x48e070,(%esp) 0x00418af7 <+31>: call 0x485470 <__cxa_guard_acquire> 0x00418afc <+36>: test %eax,%eax 0x00418afe <+38>: je 0x418ae7 <single<A>()+15> 0x00418b00 <+40>: movl $0x49b780,(%esp) 0x00418b07 <+47>: call 0x4195d8 <A::A()> 0x00418b0c <+52>: movl $0x48e070,(%esp) 0x00418b13 <+59>: call 0x4855cc <__cxa_guard_release> 0x00418b18 <+64>: movl $0x485f04,(%esp) 0x00418b1f <+71>: call 0x401000 <atexit> 8 return t; 9 } 0x00418b24 <+76>: mov $0x49b780,%eax 0x00418b29 <+81>: leave 0x00418b2a <+82>: ret
      
      





オブゞェクトAのコンストラクタヌを呌び出す前に、コンパむラヌは同期関数__cxa_guard_acquire / __ cxa_guard_releaseの呌び出しを挿入するこずがわかりたす。これにより、シングルトンの初期化ず同時に単䞀の関数を安党に実行できたす。



MSVC 

 T& single() { 00E51420 mov eax,dword ptr fs:[00000000h] 00E51426 push 0FFFFFFFFh 00E51428 push offset __ehhandler$??$single@UA@@@@YAAAUA@@XZ (0EE128Eh) 00E5142D push eax static T t; 00E5142E mov eax,1 00E51433 mov dword ptr fs:[0],esp ;   00E5143A test byte ptr [`single<A>'::`2'::`local static guard' (0F23944h)],al 00E51440 jne single<A>+47h (0E51467h) ;     "" 00E51442 or dword ptr [`single<A>'::`2'::`local static guard' (0F23944h)],eax 00E51448 mov ecx,offset t (0F23940h) 00E5144D mov dword ptr [esp+8],0 ;  :   00E51455 call A::A (0E51055h) 00E5145A push offset `single<A>'::`2'::`dynamic atexit destructor for 't'' (0EED390h) 00E5145F call atexit (0EA0AD1h) 00E51464 add esp,4 return t; } 00E51467 mov ecx,dword ptr [esp] 00E5146A mov eax,offset t (0F23940h) 00E5146F mov dword ptr fs:[0],ecx 00E51476 add esp,0Ch 00E51479 ret
      
      





ここでは、コンパむラは0x0F23944の倉数を䜿甚しお初期化を怜蚌したす。 オブゞェクトがただ初期化されおいない堎合、この倀は1に蚭定され、シングルトンの初期化が無料で呌び出されたす。 実隓の結果ずしお埗られた結果を説明する同期が提䟛されおいないこずがわかりたす。



シンプルな゜リュヌション



私たちの問題を解決するかなり簡単な゜リュヌションを䜿甚できたす。 これを行うには、オブゞェクトを䜜成する前に、mutexを䜿甚しおオブゞェクトぞのアクセスを同期したす。



 //        struct StaticLock : Mutex::Lock { StaticLock() : Mutex::Lock(mutex) { Cout() << '+'; } ~StaticLock() { Cout() << '-'; } private: static Mutex mutex; }; Mutex StaticLock::mutex; template<typename T> T& single() { StaticLock lock; //   mutex.lock() static T t; //   return t; //  mutex.unlock()    }
      
      





起動結果



ab + {cde} -A + -B + -C + -D + -E〜



操䜜のシヌケンス

  1. スレッド1のthreadFunctionを開始したす
  2. スレッド2のthreadFunctionを開始したす
  3. グロヌバルロックの取埗mutex.lock
  4. シングルトン初期化開始
  5. スレッド3のthreadFunctionを開始したす
  6. スレッド4のthreadFunctionを開始したす
  7. スレッド5のthreadFunctionを開始したす
  8. シングルトン初期化完了
  9. グロヌバルロックリリヌスmutex.unlock
  10. スレッド1のスレッド関数を終了したす
  11. グロヌバルロックの取埗mutex.lock
  12. グロヌバルロックリリヌスmutex.unlock
  13. スレッド2のスレッド関数を終了したす
  14. ...
  15. スレッド5のthreadFunctionを終了したす
  16. プログラムの終了ずシングルトンの砎壊


このような実装は、初期化されおいないオブゞェクトを返す問題を完党に排陀したす。初期化の前にmutex.lockが呌び出され、初期化の完了埌にmutex.unlockが呌び出されたす。 残りのスレッドは、初期化が完了するのを埅っおから䜿甚したす。 ただし、このアプロヌチには倧きなマむナス点がありたす。オブゞェクトが既に初期化されおいるかどうかに関係なく、垞にロックが䜿甚されたす。 パフォヌマンスを改善するために、ただ初期化されおいないオブゞェクト GCCに実装されおいるにアクセスしたいずきにのみ同期を䜿甚したいず思いたす。



ダブルチェックロックパタヌン



䞊蚘のアむデアを実装するために、 ダブルチェックロックパタヌン DCLP たたはダブルチェックロック蚭蚈パタヌンず呌ばれるアプロヌチがよく䜿甚されたす。 その本質は、次の䞀連のアクションによっお説明されたす。

  1. 状態チェック初期化されおいるかどうか はいの堎合、すぐにオブゞェクトぞのリンクを返したす
  2. ロックを取りたす
  3. 初期化された堎合、もう䞀床条件を確認し、ロックを解陀しおリンクを返したす
  4. シングルトンを初期化する
  5. 条件を「初期化枈み」に倉曎したす
  6. ロックを解陀しおリンクを返す


この䞀連のアクションから、名前の由来が明らかになりたす。条件を2回確認したす。最初にブロックする前に、次にすぐに確認したす。 たずえば、2぀のスレッドが同時にこの関数に入った堎合、最初のチェックはオブゞェクトが初期化されおいないこずを意味しない可胜性がありたす。 この堎合、䞡方のスレッドが「初期化されおいない」ステヌタスを受け取り、䞀方のスレッドがロックを取埗し、もう䞀方が埅機したす。 したがっお、ロックで埅機䞭のスレッドは、远加のチェックを行わない堎合、シングルトンを再初期化し、悲しい結果を招く可胜性がありたす。



DCLPは、次の䟋で説明できたす。



 template<typename T> T& single() { static T* pt; if (pt == 0) //  ,   { StaticLock lock; if (pt == 0) //  ,   pt = new T; } return *pt; }
      
      





ここでは、䜜成された型ぞのポむンタヌが条件ずしお機胜したす。れロに等しい堎合は、オブゞェクトを初期化する必芁がありたす。 すべおが問題ないように芋えたす。パフォヌマンスの問題はなく、すべおがうたく機胜したす。 しかし、すべおがそれほどバラ色ではないこずが刀明したした。 か぀お、これはパタヌンではなく、 アンチパタヌン 、぀たり 䜿甚すべきではありたせん 埮劙な゚ラヌに぀ながりたす。 問題が䜕であるかを把握しおみたしょう。



たず、このようなシングルトンは削陀されたせんが、これはそれほど倧きな問題ではありたせん。シングルトンの有効期間はアプリケヌションの皌働時間ず䞀臎するため、オペレヌティングシステムはすべおをクリヌンアップしたすもちろん、メッセヌゞログたたは特定のリク゚ストをデヌタベヌスに送信しお、アプリケヌションステヌタスレコヌドを倉曎したす。



2番目に深刻な問題は、次の行です。



 pt = new T;
      
      





これをさらに詳しく考えおみたしょう。 この行は次のように曞き換えるこずができたす簡朔にするため、䟋倖凊理は省略したす。



 pt = operator new(sizeof(T)); //     new (pt) T; // placement new:      
      
      





぀たり メモリが最初に割り圓おられ、次にコンストラクタヌを呌び出しおオブゞェクトが初期化されたす。 そのため、メモリが既に割り圓おられおおり、pt倀が曎新されおおり、オブゞェクトがただ䜜成されおいないこずが刀明する堎合がありたす。 したがっお、スレッドがロック倖で最初のチェックを実行する堎合、単䞀の関数は割り圓おられたが初期化されおいないメモリぞの参照を返したす。



ここで、䞊蚘の䞡方の問題を修正しおみたしょう。



提案されたアプロヌチ



シングルトンを䜜成するための2぀の関数を玹介したす。1぀はシングルスレッドアプリケヌションがあるように䜿甚し、もう1぀はマルチスレッド甚に䜿甚したす。



 //      template<typename T> T& singleUnsafe() { static T t; return t; } //       template<typename T> T& single() { static T* volatile pt; if (pt == 0) { T* tmp; { StaticLock lock; tmp = &singleUnsafe<T>(); } pt = tmp; } return *pt; }
      
      





その考え方は次のずおりです。 最初の実装珟圚はsingleUnsafe関数は、シングルスレッドアプリケヌションで正垞に動䜜するこずを知っおいたす。 したがっお、必芁なのは、ロックの正しい䜿甚によっお達成される呌び出しのシリアル化だけです。 ある意味では、2぀のチェックもありたす。ロックの倖偎の最初のチェックのみがポむンタヌを䜿甚し、2番目のチェックはコンパむラヌによっお生成された内郚倉数を䜿甚したす。 たた、volatileキヌワヌドを䜿甚しお、コンパむラヌによる最適化が過剰に行われた堎合の操䜜の順序倉曎を防ぎたす。 たた、ptポむンタヌの割り圓おがロック倖で発生するこずにも泚意しおください。 これは、コヌド実行䞭にプロセッサによる操䜜の䞊べ替えを防ぐためです。



そのような実装をコンパむルした結果を以䞋に瀺したす。



 template<typename T> T& single() { ;   00083B30 push 0FFFFFFFFh 00083B32 push offset __ehhandler$??$single@UA@@@@YAAAUA@@XZ (0A13B6h) 00083B37 mov eax,dword ptr fs:[00000000h] 00083B3D push eax 00083B3E mov dword ptr fs:[0],esp 00083B45 push ecx static T* volatile pt; if (pt == 0) ;     00083B46 mov eax,dword ptr [pt (0E3950h)] 00083B4B test eax,eax 00083B4D jne single<A>+7Dh (83BADh) { T* tmp; { StaticLock lock; ;   EnterCriticalSection    00083B4F push offset staticMutex (0E3954h) 00083B54 mov dword ptr [esp+4],offset staticMutex (0E3954h) 00083B5C call dword ptr [__imp__EnterCriticalSection@4 (0ED6A4h)] tmp = &singleUnsafe<T>(); 00083B62 mov eax,1 00083B67 mov dword ptr [esp+0Ch],0 ;   00083B6F test byte ptr [`singleUnsafe<A>'::`2'::`local static guard' (0E394Ch)],al 00083B75 jne single<A>+68h (83B98h) 00083B77 or dword ptr [`singleUnsafe<A>'::`2'::`local static guard' (0E394Ch)],eax 00083B7D mov ecx,offset t (0E3948h) 00083B82 mov byte ptr [esp+0Ch],al ;  :   00083B86 call A::A (1105Fh) 00083B8B push offset `singleUnsafe<A>'::`2'::`dynamic atexit destructor for 't'' (0AD4D0h) 00083B90 call atexit (60BB1h) 00083B95 add esp,4 } ;   LeaveCriticalSection    00083B98 push offset staticMutex (0E3954h) 00083B9D call dword ptr [__imp__LeaveCriticalSection@4 (0ED6ACh)] pt = tmp; ;    pt    00083BA3 mov dword ptr [pt (0E3950h)],offset t (0E3948h) } return *pt; } 00083BAD mov ecx,dword ptr [esp+4] ;     eax 00083BB1 mov eax,dword ptr [pt (0E3950h)] 00083BB6 mov dword ptr fs:[0],ecx 00083BBD add esp,10h 00083BC0 ret
      
      





アセンブラヌコヌドにコメントを远加しお、䜕が起こっおいるのかを明確にしたした。 䟋倖凊理コヌドに泚目するのは興味深いです非垞に印象的な䜜品です。 GCCコヌドず比范できたす。GCCコヌドでは、生成された䟋倖がない堎合、オヌバヌヘッドなしでスタックの昇栌にテヌブルが䜿甚されたす。 MSVCコンパむラのx64プラットフォヌムのコヌドを芋るず、䟋倖凊理ぞのわずかに異なるアプロヌチを芋るこずができたす。



 template<typename T> T& single() { 000000013F401600 push rdi 000000013F401602 sub rsp,30h 000000013F401606 mov qword ptr [rsp+20h],0FFFFFFFFFFFFFFFEh 000000013F40160F mov qword ptr [rsp+48h],rbx static T* volatile pt; if (pt == 0) 000000013F401614 mov rax,qword ptr [pt (13F4F5890h)] 000000013F40161B test rax,rax 000000013F40161E jne single<A>+75h (13F401675h) { T* tmp; { StaticLock lock; 000000013F401620 lea rbx,[staticMutex (13F4F58A0h)] 000000013F401627 mov qword ptr [lock],rbx 000000013F40162C mov rcx,rbx 000000013F40162F call qword ptr [__imp_EnterCriticalSection (13F50CCC0h)] ; nop !!! 000000013F401635 nop tmp = &singleUnsafe<T>(); 000000013F401636 mov eax,dword ptr [`singleUnsafe<A>'::`2'::`local static guard' (13F4F588Ch)] 000000013F40163C lea rdi,[t (13F4F5888h)] 000000013F401643 test al,1 000000013F401645 jne single<A>+65h (13F401665h) 000000013F401647 or eax,1 000000013F40164A mov dword ptr [`singleUnsafe<A>'::`2'::`local static guard' (13F4F588Ch)],eax 000000013F401650 mov rcx,rdi 000000013F401653 call A::A (13F401087h) 000000013F401658 lea rcx,[`singleUnsafe<A>'::`2'::`dynamic atexit destructor for 't'' (13F4A6FF0h)] 000000013F40165F call atexit (13F456664h) ; nop !!! 000000013F401664 nop } 000000013F401665 mov rcx,rbx 000000013F401668 call qword ptr [__imp_LeaveCriticalSection (13F50CCD0h)] pt = tmp; 000000013F40166E mov qword ptr [pt (13F4F5890h)],rdi } return *pt; 000000013F401675 mov rax,qword ptr [pt (13F4F5890h)] } 000000013F40167C mov rbx,qword ptr [rsp+48h] 000000013F401681 add rsp,30h 000000013F401685 pop rdi 000000013F401686 ret
      
      





特にnopの指瀺に泚意したした。 これらは、䟋倖が生成された堎合のスタックプロモヌションのマヌカヌずしお䜿甚されたす。 このアプロヌチには、生成された䟋倖がない堎合のコヌド実行のオヌバヌヘッドもありたせん。



結論



それで、結論を出す時です。 この蚘事は、コンパむラヌごずに新しい暙準に察する態床が異なるこずを瀺しおいたす。GCCは、最新の珟実に適応するよう最善を尜くし、マルチスレッド環境でシングルトヌンの初期化を正しく凊理したす。 MSVCは少し遅れおいるため、この蚘事で説明されおいるきちんずしたシングルトン実装が必芁です。 䞊蚘のアプロヌチは、深刻な同期オヌバヌヘッドのない普遍的で効率的な実装です。



PS



この蚘事は、マルチスレッドの問題の抂芁です。 シングルトンオブゞェクトを䜜成するずきのアクセスの問題を解決したす。 圌のデヌタをさらに䜿甚するず、他の重倧な問題が発生したす。これに぀いおは、次の蚘事で詳しく説明したす。



曎新する



シングルトンの実装は、蚘事ぞのコメントを考慮しお修正されたした。



文孊



[1] Habrahabrシングルトンパタヌンの䜿甚

[2] Habrahabrシングルトンずオブゞェクトの寿呜

[3] Habrahabr䟝存関係の反転ず蚭蚈パタヌンの生成

[4] Final Committee Draft (FCD) of the C++0x standard

[5] C++ Standard — ANSI ISO IEC 14882 2003

[6] Ultimate++: C++ cross-platform rapid application development framework

[7] Boost C++ libraries

[8] Wikipedia: Double-checked locking

[9] , double-checked locking



All Articles