ã¯ããã«
çŸæç¹ã§ã¯ãåäžã®ã¹ã¬ããã§å®è¡ããããœãããŠã§ã¢ãæ³åããããšã¯å°é£ã§ãã ãã¡ããã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ã®threadFunctionãéå§ããŸã
- ã¹ã¬ãã2ã®threadFunctionãéå§ããŸã
- ã·ã³ã°ã«ãã³åæåéå§
- ã¹ã¬ãã3ã®threadFunctionãéå§ããŸã
- ã¹ã¬ãã4ã®threadFunctionãéå§ããŸã
- ã¹ã¬ãã5ã®threadFunctionãéå§ããŸã
- ã·ã³ã°ã«ãã³åæåå®äº
- ãã¹ãŠã®ã¹ã¬ãã1ã5ã«å¯ŸããŠthreadFunctionãé 次çµäº
- ããã°ã©ã ã®çµäºãšã·ã³ã°ã«ãã³ã®ç Žå£
ã·ã³ã°ã«ãã³ã¯äžåºŠã ãåæåãããthreadFunctioné¢æ°ã¯ãã·ã³ã°ã«ãã³ã®åæå=> GCCããã«ãã¹ã¬ããç°å¢ã§ãªããžã§ã¯ããæ£ããåæåããåŸã«ã®ã¿äœæ¥ãçµäºããŸãã
MSVCã®ç¶æ³ã¯å€å°ç°ãªããŸãã
- ã¹ã¬ãã1ã®threadFunctionãéå§ããŸã
- ã¹ã¬ãã2ã®threadFunctionãéå§ããŸã
- ã·ã³ã°ã«ãã³åæåéå§
- ãšã©ãŒïŒã·ã³ã°ã«ãã³ãåæåãããŠããŸãã
- ã¹ã¬ãã3ã®threadFunctionãéå§ããŸã
- ã¹ã¬ãã2ã®ã¹ã¬ããé¢æ°ãçµäºããŸã
- ãšã©ãŒïŒã·ã³ã°ã«ãã³ãåæåãããŠããŸãã
- ...
- ã¹ã¬ãã5ã®threadFunctionãçµäºããŸã
- ã·ã³ã°ã«ãã³åæåå®äº
- ã¹ã¬ãã1ã®ã¹ã¬ããé¢æ°ãçµäºããŸã
- ããã°ã©ã ã®çµäºãšã·ã³ã°ã«ãã³ã®ç Žå£
ãã®å Žåãæåã®ã¹ããªãŒã ã®ã³ã³ãã€ã©ãŒã¯ã·ã³ã°ã«ãã³ã®åæåãéå§ããæ®ãã®ã³ã³ãã€ã©ãŒã¯åæåããæéãããªãã£ããªããžã§ã¯ããçŽã¡ã«è¿ããŸãã ãããã£ãŠã 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ã®threadFunctionãéå§ããŸã
- ã¹ã¬ãã2ã®threadFunctionãéå§ããŸã
- ã°ããŒãã«ããã¯ã®ååŸïŒmutex.lockïŒïŒ
- ã·ã³ã°ã«ãã³åæåéå§
- ã¹ã¬ãã3ã®threadFunctionãéå§ããŸã
- ã¹ã¬ãã4ã®threadFunctionãéå§ããŸã
- ã¹ã¬ãã5ã®threadFunctionãéå§ããŸã
- ã·ã³ã°ã«ãã³åæåå®äº
- ã°ããŒãã«ããã¯ãªãªãŒã¹ïŒmutex.unlockïŒïŒ
- ã¹ã¬ãã1ã®ã¹ã¬ããé¢æ°ãçµäºããŸã
- ã°ããŒãã«ããã¯ã®ååŸïŒmutex.lockïŒïŒ
- ã°ããŒãã«ããã¯ãªãªãŒã¹ïŒmutex.unlockïŒïŒ
- ã¹ã¬ãã2ã®ã¹ã¬ããé¢æ°ãçµäºããŸã
- ...
- ã¹ã¬ãã5ã®threadFunctionãçµäºããŸã
- ããã°ã©ã ã®çµäºãšã·ã³ã°ã«ãã³ã®ç Žå£
ãã®ãããªå®è£ ã¯ãåæåãããŠããªããªããžã§ã¯ããè¿ãåé¡ãå®å šã«æé€ããŸããåæåã®åã«mutex.lockïŒïŒãåŒã³åºãããåæåã®å®äºåŸã«mutex.unlockïŒïŒãåŒã³åºãããŸãã æ®ãã®ã¹ã¬ããã¯ãåæåãå®äºããã®ãåŸ ã£ãŠãã䜿çšããŸãã ãã ãããã®ã¢ãããŒãã«ã¯å€§ããªãã€ãã¹ç¹ããããŸãããªããžã§ã¯ããæ¢ã«åæåãããŠãããã©ããã«é¢ä¿ãªããåžžã«ããã¯ã䜿çšãããŸãã ããã©ãŒãã³ã¹ãæ¹åããããã«ããŸã åæåãããŠããªããªããžã§ã¯ãïŒ GCCã«å®è£ ãããŠããïŒã«ã¢ã¯ã»ã¹ããããšãã«ã®ã¿åæã䜿çšããããšæããŸãã
ããã«ãã§ãã¯ããã¯ãã¿ãŒã³
äžèšã®ã¢ã€ãã¢ãå®è£ ããããã«ã ããã«ãã§ãã¯ããã¯ãã¿ãŒã³ïŒ DCLP ïŒãŸãã¯ããã«ãã§ãã¯ããã¯èšèšãã¿ãŒã³ãšåŒã°ããã¢ãããŒãããã䜿çšãããŸãã ãã®æ¬è³ªã¯ã次ã®äžé£ã®ã¢ã¯ã·ã§ã³ã«ãã£ãŠèª¬æãããŸãã
- ç¶æ ãã§ãã¯ïŒåæåãããŠãããã©ãã ã¯ãã®å Žåãããã«ãªããžã§ã¯ããžã®ãªã³ã¯ãè¿ããŸã
- ããã¯ãåããŸã
- åæåãããå ŽåãããäžåºŠæ¡ä»¶ã確èªããããã¯ã解é€ããŠãªã³ã¯ãè¿ããŸã
- ã·ã³ã°ã«ãã³ãåæåãã
- æ¡ä»¶ããåæåæžã¿ãã«å€æŽããŸã
- ããã¯ã解é€ããŠãªã³ã¯ãè¿ã
ãã®äžé£ã®ã¢ã¯ã·ã§ã³ãããååã®ç±æ¥ãæããã«ãªããŸããæ¡ä»¶ã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