次ã«ã contfree_safe_ptr <std :: map>ã®äœæ¥ããstd :: map <>ãšæ©èœçã«é¡äŒŒããè€éã§æé©åãããããã¯ããªãŒããŒã¿æ§é ã®ã¬ãã«ãŸã§é«éåããæ¹æ³ã瀺ããŸãã com / khizmax / libcds
ãŸããcontfree_safe_ptr <T>ãšããŠäœ¿çšãããæåã®ã¹ã¬ããã»ãŒãã¯ã©ã¹Tã®ãããã§ãããã®ãããªãã«ãã¹ã¬ããããã©ãŒãã³ã¹ãåŸãããšãã§ããŸãã çç£æ§ãçŽ1000ïŒ åäžãããæé©åã«é¢å¿ãããããã匱ããŠçãããæé©åã«ã¯æ³šæãæããŸããã
é¢é£ãã3ã€ã®èšäºïŒ
- ãªããžã§ã¯ããã¹ã¬ããã»ãŒãã«ãã
- stdã®é«éå:: shared_mutexã10å
- ã¹ã¬ããã»ãŒãstd ::ããã¯ã®ãªããããããã©ãŒãã³ã¹ãåããããã
â ç§ã®è±èªã®èšäº
â 3ã€ã®èšäºãã¹ãŠã®äŸãšãã¹ã
é«æ§èœããã¯ããŒã¹ã®ããŒã¿æ§é
contfree_safe_ptr <T>ã¯ã¯ã©ã¹safe_ptr <Tãcontention_free_shared_mutex>ã§ããcontention_free_shared_mutexã¯ãç¬èªã®æé©åãããå ±æmutexã§ãã ãŸããsafe_ptrã¯ååã®èšäºã®ã¹ã¬ããã»ãŒããã€ã³ã¿ãŒã§ãã
é çªã«ãç¬èªã®é«æ§èœã§ç«¶åã®ãªãshared-mutexãå®è£ ããæ¹æ³ã瀺ããŸããããã¯ãèªã¿åãã§ã»ãšãã©ç«¶åããŸããã æŽæ°æäœã§è¡ããããã¯ããããã«ãç¬èªã®ã¢ã¯ãã£ãã¹ãã³ããã¯ããã³ååž°ã¹ãã³ããã¯ããã¯ãå®è£ ããŸãã RAIIããããã³ã°ãã€ã³ã¿ãŒãäœæããŠãè€æ°ã®ããããã³ã°ã®ã³ã¹ããåé¿ããŸãã ããã©ãŒãã³ã¹ãã¹ãã®çµæã¯æ¬¡ã®ãšããã§ãã
ãŸããã楜ãã¿ã®ãããã®ããŒãã¹ãšããŠãåã»ã¯ã·ã§ã³ã®å¢çãæåã«ããã£ãŠããå ŽåãDBMSã®ããŒãã£ã·ã§ã³ããŒãã«ã«äŒŒãè€æ°ã®std ::ãããã§æ§æãããããã«ãã¹ã¬ããçšã«ããã«æé©åãããç¬èªã®åçŽåããŒãã£ã·ã§ã³ã¿ã€ãpartition_mapã®ã¯ã©ã¹ãå®è£ ããæ¹æ³ã瀺ããŸãã
ååæäœã®åºç€
ãã«ãã¹ã¬ãããååæ§ãã¡ã¢ãªããªã¢ã®åºæ¬ãèæ ®ããŠãã ããã è€æ°ã®ã¹ã¬ããããåãããŒã¿ãå€æŽããå Žåãã€ãŸã thread_funcïŒïŒé¢æ°ãè€æ°ã®ã¹ã¬ããã§åæã«å®è¡ããå ŽåïŒ
int a; void thread_func() { a = a + 1; } // wrong: data-race
次ã«ãthread_funcïŒïŒé¢æ°ãåŒã³åºãåã¹ã¬ããã¯ãéåžžã®å ±æå€æ°int aã«1ãè¿œå ããŸãã ãã®ãããªã³ãŒãã¯äžè¬ã«ã¹ã¬ããã»ãŒãã§ã¯ãããŸããã éåžžã®å€æ°ã«å¯Ÿããè€åæäœïŒRMW-èªã¿åã-å€æŽ-æžã蟌ã¿ïŒã¯ãå¥ã®ã¹ã¬ãããããŒã¿ãå€æŽã§ããå€ãã®å°ããªæäœã§æ§æãããŸãã æäœa = a + 1; å°ãªããšã3ã€ã®ãããªãã¬ãŒã·ã§ã³ã§æ§æãããŸãã
- å€æ°ãaãã®å€ãããã»ããµã¬ãžã¹ã¿ã«ããŒãããŸã
- ã¬ãžã¹ã¿ã®å€ã«1ãå ç®ããŸã
- ã¬ãžã¹ã¿ã®å€ãå€æ°ãaãã«æžãæ»ããŸã
ããšãã°ãint a = 0; ãŸãã2ã€ã®ã¹ã¬ãããæäœa = a + 1ãå®è¡ããŸãã çµæã¯a = 2ã«ãªããŸãã ãããã次ã®ããšãèµ·ããå¯èœæ§ããããŸã-ã¹ããããã€ã¹ãããïŒ
int a = 0; // register1 = ?, register2 = ?, a = 0 Thread 1: register1 = a; // register1 = 0, register2 = ?, a = 0 Thread 2: register2 = a; // register1 = 0, register2 = 0, a = 0 Thread 1: register1++; // register1 = 1, register2 = 0, a = 0 Thread 2: register2++; // register1 = 1, register2 = 1, a = 0 Thread 1: a = register1; // register1 = 1, register2 = 1, a = 1 Thread 2: a = register2; // register1 = 1, register2 = 1, a = 1
2ã€ã®ã¹ããªãŒã ãåãã°ããŒãã«å€æ°+1ã«è¿œå ãããŸãããæçµçã«å€æ°a = 1ã§ãããã®åé¡ã¯ããŒã¿ã¬ãŒã¹ãšåŒã°ããŸãã
ãã®åé¡ãåé¿ããã«ã¯3ã€ã®æ¹æ³ããããŸãã
- ã¢ãããã¯å€æ°ã§ã¢ãããã¯åœä»€ã䜿çšããŸããã1ã€ã®æ¬ ç¹ããããŸããã¢ãããã¯é¢æ°ã®æ°ã¯éåžžã«å°ãªãããããããã䜿çšããŠè€éãªããžãã¯ãå®è£ ããããšã¯å°é£ã§ãã
- æ°ããã³ã³ããããšã«ç¬èªã®è€éãªããã¯ããªãŒã¢ã«ãŽãªãºã ãéçºããŸãã
- ããã¯ã䜿çšããïŒstd :: mutexãstd :: shared_timed_mutexãspinlock ...ïŒ-ãããã¯ãããã³ãŒããžã®1ã€ã®ã¹ããªãŒã ãé çªã«èš±å¯ãããããããŒã¿ç«¶åã¯çºçãããéåžžã®ã¹ã¬ããã»ãŒãã§ãªãä»»æã®è€éãªããžãã¯ã䜿çšã§ããŸããªããžã§ã¯ãã
std :: atomic <int> a; æåã«a = 0ã®å Žå; ãŸãã2ã€ã®ã¹ã¬ãããæäœa + = 1ãå®è¡ããŸãã çµæã¯åžžã«a = 2ã«ãªããŸãã
std::atomic<int> a; void thread_func() { a += 1; } // correct: no data-race
次ã¯x86_64ããã»ããµã§åžžã«çºçããŸãïŒã¹ããããã€ã¹ãããïŒã
std::atomic<int> a = 0; // register1 = ?, register2 = ?, a = 0 Thread 1: register1 = a; // register1 = 0, register2 = ?, a = 0 Thread 1: register1++; // register1 = 1, register2 = ?, a = 0 Thread 1: a = register1; // register1 = 1, register2 = ?, a = 1 Thread 2: register2 = a; // register1 = 1, register2 = 1, a = 1 Thread 2: register2++; // register1 = 1, register2 = 2, a = 1 Thread 2: a = register2; // register1 = 1, register2 = 2, a = 2
ARMãPowerPCãªã©ãLL / SCããµããŒãããããã»ããµãŒã§ã¯ãä»ã®æé ãçºçããŸãããåãçµæa = 2ãçºçããŸãã
C ++ 11ã§å°å ¥ãããã¢ãããã¯å€æ°ïŒ en.cppreference.com/w/cpp/atomic/atomic
std :: atomic <>ã¯ã©ã¹ãã³ãã¬ãŒãã®ã¡ã³ããŒã§ããé¢æ°ã¯åžžã«ã¢ãããã¯ã§ãã
以äžã«ãæ£ããã³ãŒãã®3ã€ã®ãã©ã°ã¡ã³ãã瀺ããŸããæå³ã¯åãã§ãã
1.äŸïŒ
std::atomic<int> a; a = 20; a += 50;
2.ããã¯äŸ1ãšåãã§ãã
std::atomic<int> a; a.store( 20 ); a.fetch_add( 50 );
3.ãããŠãããã¯äŸ1ãšåãã§ãã
std::atomic<int> a; a.store( 20, std::memory_order_seq_cst ); a.fetch_add( 50, std::memory_order_seq_cst );
ã€ãŸããstd :: atomicã®å ŽåïŒ
- loadïŒïŒããã³storeïŒïŒã¯ã æŒç®åTããã³æŒç®å=ãšåãã§ãã
- fetch_addïŒïŒããã³fetch_subïŒïŒã¯ã operator + =ããã³operator- =ãšåãã§ã
- Sequential ConsistencyïŒstd :: memory_order_seq_cstïŒã¯ãããã©ã«ãã®ã¡ã¢ãªããªã¢ã§ãïŒæãå³æ Œã§ä¿¡é Œæ§ããããŸãããä»ãšæ¯èŒããŠæãäœéã§ãïŒã
C ++ 11ã®std :: atomicãšvolatileã®éãã«æ³šæããŠãã ããïŒ www.drdobbs.com/parallel/volatile-vs-volatile/212701484
5ã€ã®äž»ãªéãããããŸãã
- æé©å ïŒstd :: Atomic <T> a; æ®çºæ§T aã§ã¯äžå¯èœãª2ã€ã®æé©åãå¯èœã§ãã
â¢ããŒãžã®æé©åïŒa = 10; a = 20; = 20ã®ã³ã³ãã€ã©ãŒã«çœ®ãæããããšãã§ããŸãã
â¢å®æ°çœ®æã®æé©åïŒa = 1; ããŒã«ã«= a; = 1ã³ã³ãã€ã©ã§çœ®ãæããããšãã§ããŸãã ããŒã«ã«= 1; - 䞊ã¹æ¿ã ïŒstdã®æäœ:: atomic <T> a; 䜿çšãããŠããã¡ã¢ãªããªã¢std :: memory_order_ ...ã«åŸã£ãŠãéåžžã®å€æ°ã䜿çšããæäœããã³ä»ã®ã¢ãããã¯å€æ°ã䜿çšããæäœã«ã€ããŠãããèªäœã®åšãã®äžŠã¹æ¿ããå¶éã§ããŸãã éåžžã®å€æ°ïŒéåå/äžæ®çºæ§ïŒã®é åºã«ã¯åœ±é¿ããŸãããããã¹ãŠã®æ®çºæ§å€æ°ã®åŒã³åºãã¯åžžã«å³å¯ãªçžäºé åºãç¶æããŸãã 2ã€ã®æ®çºæ§æäœã®å®è¡é åºã¯ãã³ã³ãã€ã©ãŒã§ã¯ãªããããã»ããµãŒã§å€æŽã§ããŸãã
- ã¹ãã«ïŒã¡ã¢ãªããªã¢std :: memory_order_releaseãstd :: memory_order_acq_relãstd :: memory_order_seq_cstãstd :: atomic <T> aã®æäœã«æå®ãããŠããŸãã ã¢ãããã¯æäœãå®è¡ããåã«ããã¹ãŠã®å ±éå€æ°ã®æµåºãéå§ããŸãã ã€ãŸã ãããã®ããªã¢ã¯ãã³ã³ãã€ã©ããã®ããŒã«ã«å€æ°ãä»ã®ã¹ã¬ããã§äœ¿çšã§ããªãããšã100ïŒ ä¿èšŒã§ããªãéããããã»ããµã¬ãžã¹ã¿ããRAM /ãã£ãã·ã¥ã«éåžžã®å€æ°ãã¢ã³ããŒãããŸãã
- Atomicity / Alignment ïŒstdã«å¯Ÿããæäœ:: atomic <T> a; ä»ã®ã¹ããªãŒã ã«å®å šã«è¡šç€ºããããããŸã£ãã衚瀺ãããŸããã æŽæ°åTã®å Žåãããã¯ã³ã³ãã€ã©ãŒã«ãã£ãŠã¡ã¢ãªå ã®ã¢ãããã¯å€æ°ã®äœçœ®ã調æŽããããšã§å®çŸãããŸã-å°ãªããšãå€æ°ã¯1ã€ã®ãã£ãã·ã¥ã©ã€ã³ã«ååšããå¿ èŠããããããã¢ãããã¯å€æ°ã¯1åã®CPUæäœã§å€æŽãŸãã¯èªã¿åãã§ããŸã éã«ãã³ã³ãã€ã©ã¯ãæ®çºæ§å€æ°ã®ã¢ã©ã€ã¡ã³ããšãããã«å¯Ÿããæäœã®ã¢ãããã¯æ§ãä¿èšŒããŸããã æ®çºæ§å€æ°ã¯éåžžãããã€ã¹ã¡ã¢ãªãžã®ã¢ã¯ã»ã¹ããã®ä»ã®å Žåã«äœ¿çšãããŸãããã¹ã¬ããéã®ããŒã¿äº€æã«ã¯äœ¿çšãããŸããã ããã€ã¹ãã©ã€ããŒAPIã¯ãæ®çºæ§å€æ°ãžã®ãã€ã³ã¿ãŒãè¿ããŸããå¿ èŠã«å¿ããŠããã®APIã¯ã¢ã©ã€ã¡ã³ããæäŸããŸãã
- RMWæäœã®ã¢ãããã¯æ§ ïŒèªã¿åã-å€æŽ-æžã蟌ã¿ïŒïŒstd ã«å¯Ÿããæäœ :: atomic <T> a; ïŒ++ã-ã+ =ã-=ã* =ã/ =ãCASã亀æïŒãªã©ã¯ãã¢ãããã¯ã«å®è¡ãããŸãã 2ã€ã®ã¹ã¬ããã++ aæäœãå®è¡ããå Žå; ãã®å€æ°ã¯ããã£ãã·ã¥ã©ã€ã³ïŒx86_64ïŒããããã¯ããããRMWæäœã®å šæéã«ããã£ãŠLL / SCïŒARMãPowerPCïŒããµããŒãããããã»ããµãŒã®ãã£ãã·ã¥ã©ã€ã³ã«å€æŽããªãããšãããŒã¯ããããšã§éæãããŸãã æ®çºæ§å€æ°ã¯ãè€åRMWæäœã®ååæ§ãæäŸããŸããã
std ::ã¢ãããã¯å€æ°ãšæ®çºæ§å€æ°ã«ã¯ã1ã€ã®äžè¬çãªã«ãŒã«ããããŸããåèªã¿åããŸãã¯æžã蟌ã¿æäœã¯ãåžžã«ã¡ã¢ãª/ãã£ãã·ã¥ã«ã¢ã¯ã»ã¹ããŸãã å€ãããã»ããµã¬ãžã¹ã¿ã«ãã£ãã·ã¥ãããããšã¯ãããŸããã
ãŸããéåžžã®ïŒéåžžã®ïŒå€æ°ãšãªããžã§ã¯ãïŒéã¢ãããã¯/äžæ®çºæ§ïŒã«ã€ããŠã¯ãã³ã³ãã€ã©ãŸãã¯ããã»ããµã«ããçžäºã®ç¬ç«ããåœä»€ã®æé©åãšäžŠã¹æ¿ããå¯èœã§ãã
ã¡ã¢ãªããªã¢std :: memory_order_releaseãstd :: memory_order_acq_relããã³std :: memory_order_seq_cstã䜿çšããŠã¢ãããã¯å€æ°ã«ã¡ã¢ãªã«æžã蟌ãæäœã¯ãçŸåšãªã³ã«ãªã£ãŠãããã¹ãŠã®éã¢ãããã¯/äžæ®çºæ§å€æ°ã®æµåºïŒã¬ãžã¹ã¿ããã¡ã¢ãªãžã®æžã蟌ã¿ïŒãä¿èšŒããããšãæãåºããŠãã ããããã»ããµã®ç»é²ã®ç¬éïŒ en.wikipedia.org/wiki/Register_allocation#Spilling
åœä»€ã®å®è¡é åºãå€æŽãã
ã³ã³ãã€ã©ãšããã»ããµã¯åœä»€ã䞊ã¹æ¿ããŠãããã°ã©ã ãæé©åããããã©ãŒãã³ã¹ãåäžãããŸãã
GCCã³ã³ãã€ã©ãšx86_64ããã»ããµãè¡ãæé©åã®äŸã次ã«ç€ºããŸããgodbolt.org / g / n91hpt
ãã«ãµã€ãºã®ç»åïŒ
hsto.org/files/3d2/18b/c7b/3d218bc7b3584f82820f92077096d7a0.jpg
åçã®æé©åã¯äœã§ããïŒ
- GCC 7.0ã³ã³ãã€ã©ã®äžŠã¹æ¿ãïŒ
â¢ã¡ã¢ãªãšã³ããªã亀æããŸãb = 5; ã¡ã¢ãªããã¬ãžã¹ã¿int tmp_c = c;ã«ããŒãããŸãã ããã«ããããcãã®å€ãã§ããã ãæ©ãèŠæ±ããããšãã§ããããã»ããµã¯ãã®é·ãæäœã®å®äºãæåŸ ããŸãããããã»ããµã®ãã€ãã©ã€ã³ã¯æäœb = 5ã®äžŠåå®è¡ãèš±å¯ããŸãã ããã2ã€ã®æäœã¯äºãã«ç¬ç«ããŠããŸãã
â¢ã¡ã¢ãªããã¬ãžã¹ã¿int tmp_a = aãžã®ããŒããçµã¿åãããŸãã ããã³è¿œå æäœtmp_c = tmp_c + tmp_a; -çµæãšããŠã2ã€ã®åœä»€ã®ä»£ããã«ã1ã€ã®è¿œå eaxãååŸããã[rip] - x86_64ããã»ããµã«ãã䞊ã¹æ¿ãïŒ
ããã»ããµã¯ãå®éã®ã¡ã¢ãªã¬ã³ãŒãmov b [rip]ã5ãã¹ã¯ããããadd add eaxãa [rip]ãšçµã¿åãããŠã¡ã¢ãªããèªã¿åãããšãã§ããŸãã
mov b [rip]åœä»€ã䜿çšããŠã¡ã¢ãªãžã®æžã蟌ã¿ãéå§ãããšã次ã®5ãçºçããŸãããŸããå€5ãšã¢ãã¬ã¹b [rip]ãStore-bufferããŒããŠã§ã¢ãã¥ãŒã«é 眮ããããã¹ãŠã®ããã»ããµã³ã¢ã®ã¢ãã¬ã¹b [rip]å¿çã®å ŽåãCPU-Core-0ã¯b [rip]ãå«ããã£ãã·ã¥ã©ã€ã³ã«ã¹ããŒã¿ã¹ãeXclusiveããèšå®ãããã®åŸã§å®éã®å€5ãã¹ãã¢ãããã¡ããb [rip]ã§ãã®ãã£ãã·ã¥ã©ã€ã³ã«æžã蟌ãŸããŸãã x86_64ãã£ãã·ã¥ã³ããŒã¬ã³ã¹ãããã³ã«ã®è©³çŽ°MOESI / MESIF-ãã¹ãŠã®ã³ã¢ã«å³åº§ã«è¡šç€ºãããå€æŽïŒ en.wikipedia.org/wiki/MESIF_protocol
ãã®ãã¹ãŠã®æéãåŸ ããªãããã«ãå®éã®ãã£ãã·ã¥ãšã³ããªãåŸ ããã«5ãStore-Bufferã«é 眮ãããçŽåŸã«ãã¡ã¢ãªããã®èªã¿åããŸãã¯ã¬ãžã¹ã¿æäœã®å®è¡ãéå§ã§ããŸãã ããã¯ããŸãã«x86_64ããã»ããµãŒãè¡ãããšã§ãã
Intel 64ããã³IA-32ã¢ãŒããã¯ãã£ãœãããŠã§ã¢éçºè åãããã¥ã¢ã«ç¬¬3å·»ïŒ3Aã3Bã3Cããã³3DïŒïŒã·ã¹ãã ããã°ã©ãã³ã°ã¬ã€ãïŒ www-ssl.intel.com/content/dam/www/public/us/en/documents/manuals/ 64-ia-32-architectures-software-developer-system-programming-manual-325384.pdf
8.2.3.4ç°ãªãå Žæãžã®ä»¥åã®ã¹ãã¢ã§ããŒãã䞊ã¹æ¿ããããšãã§ããŸã
Intel-64ã®ã¡ã¢ãªé åºã¢ãã«ã§ã¯ã以åã®ã¹ãã¢ã䜿çšããŠå¥ã®å Žæã«ããŒãã䞊ã¹æ¿ããããšãã§ããŸãã ãã ããåãå Žæãžã®åºèã®å Žåãè·ç©ã¯äžŠã¹æ¿ããããŸããã
x86_64ãã¡ããªã®ããã»ããµã«ã¯åŒ·åãªã¡ã¢ãªã¢ãã«ããããŸãã ãŸããPowerPCãARM v7 / v8ãªã©ã®ã¡ã¢ãªã¢ãã«ã匱ãããã»ããµã¯ãããã«å€ãã®äžŠã¹æ¿ããå®è¡ã§ããŸãã
éåžžã®éåžžå€æ°ã æ®çºæ§å€æ°ã ã¢ãããã¯å€æ°ã®ã¡ã¢ãªãšã³ããªã®å¯èœãªäžŠã¹æ¿ãã®äŸã瀺ããŸãã
éåžžã®å€æ°ã®äžŠã¹æ¿ãïŒ
éåžžã®å€æ°ãå«ããã®ã³ãŒãã¯ãã³ã³ãã€ã©ãŸãã¯ããã»ããµã«ãã£ãŠæ¬¡ã®ããã«äžŠã¹æ¿ããããšãã§ããŸãã 1ã€ã®ã¹ããªãŒã å ã§ã¯ããã®æå³ã¯å€ãããŸããã ããããå€ãã®ã¹ã¬ããå ã§ã¯ããã®ãããªäžŠã¹æ¿ããããã°ã©ã ããžãã¯ã«åœ±é¿ãäžããå¯èœæ§ããããŸãã
2ã€ã®å€æ°ãæ®çºæ§ã®å Žåã次ã®äžŠã¹æ¿ããå¯èœã§ãã ã³ã³ãã€ã©ãŒã¯ãã³ã³ãã€ã«æã«volatileå€æ°ã®æäœã䞊ã¹æ¿ããããšã¯ã§ããŸããããã³ã³ãã€ã©ãŒã¯ãå®è¡æã«ããã»ããµãŒããã®äžŠã¹æ¿ããå®è¡ã§ããããã«ããŸãã
ãã®ãããªäžŠã¹æ¿ãã®ãã¹ãŠãŸãã¯äžéšã®ã¿ãé²ãããã«ãã¢ãããã¯æäœããããŸãïŒããã©ã«ãã§ã¯ãã¢ãããã¯æäœã¯æãå³ããã¡ã¢ãªããªã¢std :: memory_order_seq_cstã䜿çšããããšãæãåºããŠãã ãã ïŒïŒ
å¥ã®ã¹ã¬ããã¯ãã¡ã¢ãªå ã®å€æ°ã®å€æŽããã®å€æŽãããé åºã§æ£ç¢ºã«èŠãããšãã§ããŸãã
ã¢ãããã¯æäœã«ã¡ã¢ãªããªã¢ãæå®ããªãå Žåãæãå³å¯ãªstd :: memory_order_seq_cstããªã¢ãããã©ã«ãã§äœ¿çšãããã¢ãããã¯ãŸãã¯éã¢ãããã¯æäœã¯ãã®ãããªæäœã§äžŠã¹æ¿ããããšã¯ã§ããŸããïŒãã ããäŸå€ããããŸã-ããã«ã€ããŠã¯åŸã§èª¬æããŸãïŒã
äžèšã®å Žåãæåã«éåžžã®å€æ°aããã³bã«æžã蟌ã¿ã次ã«ã¢ãããã¯å€æ°a_atããã³b_atã«æžã蟌ã¿ãŸãããã®é åºã¯å€æŽã§ããŸããã ãŸããb_atã¡ã¢ãªãžã®æžã蟌ã¿ã¯ãa_atã¡ã¢ãªãžã®æžã蟌ã¿ãããæ©ãè¡ãããšã¯ã§ããŸããã ãã ããå€æ°aããã³bãžã®æžã蟌ã¿ã¯ãçžäºã«äžŠã¹æ¿ããããšãã§ããŸãã
ã泚æã§ããããšèšããšããããã¯å¯èœã§ãããå¿ ãããããã§ã¯ãããŸããã ã³ã³ãã€ã©ãã³ã³ãã€ã«æã«C ++ã³ãŒããæé©åããããå®è¡æã«CPUãæé©åãããã«ãã£ãŠç°ãªããŸãã
以äžã§ã¯ãèš±å¯ãããæ¹åã«åœä»€ã䞊ã¹æ¿ããããšãã§ããããã匱ãã¡ã¢ãªããªã¢ã«ã€ããŠèª¬æããŸããããã«ãããã³ã³ãã€ã©ãšããã»ããµã¯ã³ãŒããããæé©åããããã©ãŒãã³ã¹ãåäžãããããšãã§ããŸãã
ã¡ã¢ãªã¢ã¯ã»ã¹æäœã«å¯Ÿããéå£ã®äžŠã¹æ¿ã
C ++ 11æšæºã¡ã¢ãªã¢ãã«ã¯ãææ°ã®CPUã®ææ©çå®è¡ã®æ©èœã«å¯Ÿå¿ãã6çš®é¡ã®ã¡ã¢ãªããªã¢ãæäŸããŸãããããã䜿çšãããšã䞊ã¹æ¿ããå®å šã«çŠæ¢ããã®ã§ã¯ãªããå¿ èŠãªæ¹åã«ã®ã¿äœ¿çšã§ããŸãã ããã«ãããã³ã³ãã€ã©ãšããã»ããµãã³ãŒããå¯èœãªéãæé©åã§ããããã«ãªããŸãã ãŸããçŠæ¢ãããŠãã䞊ã¹æ¿ãã®æ瀺ã«ãããã³ãŒãã®æ£ç¢ºæ§ãç¶æã§ããŸãã en.cppreference.com/w/cpp/atomic/memory_order
enum memory_order { memory_order_relaxed, memory_order_consume, memory_order_acquire, memory_order_release, memory_order_acq_rel, memory_order_seq_cst };
- memory_order_consumeã ãã ããmeââmory_order_consumeããªã¢ãå®éã«ã¯äœ¿çšããªãããšã«æ³šæããŠãã ããã æšæºã¯ãã®äœ¿çšã®é©åæ§ã«çåãæ±ããŠããŸã-æšæºããã®åŒçšïŒ www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4606.pdf
§29.3
ïŒ1.3ïŒ-memory_order_consumeïŒããŒãæäœã¯ã圱é¿ãåããã¡ã¢ãªäœçœ®ã§æ¶è²»æäœãå®è¡ããŸãã [泚ïŒmemory_order_acumeãåªå ããŸããããã¯ãmemory_order_consumeããã匷åãªä¿èšŒãæäŸããŸãã å®è£ ã§ã¯ãmemory_order_acquireã®ããã©ãŒãã³ã¹ãããåªããããã©ãŒãã³ã¹ãæäŸããããšã¯å®è¡äžå¯èœã§ããããšãããã£ãŠããŸãã ä»æ§ã®æ¹èšã¯æ€èšäžã§ãã -çµäºããŒã] - memory_order_acq_relã ãŸããmemory_order_acq_relããªã¢ã¯ãcompare_exchange_weakïŒïŒ/ _ strongïŒïŒãexchangeïŒïŒãfetch_ïŒaddãsubãandãorãxorïŒãªã©ã®ã¢ãããã¯ãªååç©RMWïŒèªã¿åã-å€æŽ-æžã蟌ã¿ïŒæäœã«ã®ã¿äœ¿çšãããããšã«æ³šæããŠãã ãããååä»ãæŒç®åïŒ en.cppreference.com/w/cpp/atomic/atomic
æ®ãã®4ã€ã®ã¡ã¢ãªããªã¢ã¯ãååŸ-ã¹ãã¢ïŒïŒã«äœ¿çšãããªãããªãªãŒã¹-ããŒãïŒïŒã«äœ¿çšãããªã-ãé€ãããã¹ãŠã®æäœã«äœ¿çšã§ããŸãã
éžæããã¡ã¢ãªããªã¢ã«å¿ããŠãã³ã³ãã€ã©ãšããã»ããµã¯ããªã¢ã«å¯ŸããŠå®è¡å¯èœãªã³ãŒããç°ãªãæ¹åã«ç§»åããããšãçŠæ¢ãããŠããŸãã
ããã§ãç¢å°ã瀺ããã®ãæ£ç¢ºã«ç€ºããŸã-å Žæãå€æŽã§ãããã®ãšã§ããªããã®ã瀺ããŸãïŒ
2ã€ã®åœä»€ã§å Žæãåãæ¿ããã«ã¯ããããã®åœä»€ã®äž¡æ¹ã®éå£ããã®ãããªäº€æãèš±å¯ããå¿ èŠããããŸãã ãªããªã ããã®ä»ã®ä»»æã®ã³ãŒããã¯ãéå£ã®ãªãéåžžã®éååå€æ°ã§ãããé åºãå€æŽã§ããŸãã å·Šäžã®äŸã®Relaxed-Release-Relaxedã§ã¯ãã芧ã®ãšãã ãåãã¡ã¢ãªããªã¢ã®é åºãå€æŽã§ãããã©ããã¯ããã®é åºã«ãã£ãŠç°ãªããŸãã
ãããã®ã¡ã¢ãªããªã¢ã®æå³ãšãæãäžè¬çãªAcquire-Releaseã®äžŠã¹æ¿ãã»ãã³ãã£ã¯ã¹ãå¿ èŠãšããåçŽãªã¹ãã³ããã¯å®è£ ã䜿çšããŠåŸãããå©ç¹ãèŠãŠã¿ãŸãããã ã¹ãã³ããã¯ã¯ãstd :: mutexãšåæ§ã®äœ¿çšæ³ã«ããããã¯ã§ãã
ãŸããããã°ã©ã ã®æ¬äœã«ã¹ãã³ããã¯ã®æŠå¿µãçŽæ¥å®è£ ããŸãã ãããŠãå¥ã®ã¹ãã³ããã¯ã¯ã©ã¹ãå®è£ ããŸãã ããã¯ïŒãã¥ãŒããã¯ã¹ãã¹ãã³ããã¯...ïŒãå®è£ ããã«ã¯ãAcquire-Releaseã»ãã³ãã£ã¯ã¹ã C ++ 11 Standard§1.10.1 ïŒ3ïŒã䜿çšããå¿ èŠããããŸãïŒ www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4606 .pdf
...ããšãã°ãmutexãååŸããåŒã³åºãã¯ãmutexãæ§æããå Žæã§ååŸæäœãå®è¡ããŸãã åæ§ã«ãåããã¥ãŒããã¯ã¹ã解æŸããåŒã³åºãã¯ãåãå Žæã§è§£æŸæäœãå®è¡ããŸãã éå ¬åŒã«ã¯ã Aã§ãªãªãŒã¹æäœãå®è¡ãããšãä»ã®ã¡ã¢ãªäœçœ®ã«å¯Ÿãã以åã®å¯äœçšããåŸã§Aã§æ¶è²»ãŸãã¯ååŸæäœãå®è¡ããä»ã®ã¹ã¬ããããèŠããããã«ãªããŸãã
Acquire-Releaseã»ãã³ãã£ã¯ã¹ã®äž»ãªãã€ã³ãã¯ã 次ã®ãšããã§ããflag.loadæäœïŒstd :: memory_order_acquireïŒã®åŸã®thread-2â Thread-2âã¯ãè¡ãããå€æ°/æ§é /ã¯ã©ã¹ïŒã¢ãããã¯ãªãã®ã§ãããªãïŒã®ãã¹ãŠã®å€æŽã確èªããããšã§ãthread.1 flag.storeïŒ0ãstd :: memory_order_releaseïŒæäœãå®è¡ãããåã®ãã¹ã¬ãã-1ãã
ããã¯ïŒãã¥ãŒããã¯ã¹ãã¹ãã³ããã¯...ïŒã®äž»ãªæå³ã¯ãäžåºŠã«1ã€ã®ã¹ã¬ããã®ã¿ãå®è¡ã§ããã³ãŒãã®ã»ã¯ã·ã§ã³ãäœæããããšã§ãã è€æ°ã®ã¹ã¬ããã§äžŠè¡ããŠå®è¡ããããšã¯ã§ããŸããã ã³ãŒãã®ãã®ã»ã¯ã·ã§ã³ã¯ãã¯ãªãã£ã«ã«ã»ã¯ã·ã§ã³ãšåŒã°ããŸãã ãã®å éšã§ã¯ãstd :: atomicãªããªã©ãéåžžã®ã³ãŒãã䜿çšã§ããŸãã
ã¡ã¢ãªããªã¢ïŒã¡ã¢ãªãã§ã³ã¹ïŒ-ã¯ãªãã£ã«ã«ã»ã¯ã·ã§ã³ããã®æäœããããè¶ ããŠæ¡åŒµããªãããã«ãã³ã³ãã€ã©ãããã°ã©ã ãæé©åããªãããã«ããŸãã
æåã«ããã¯ãååŸããã¹ã¬ããã¯ãã®ã³ãŒããããã¯ãå®è¡ããæ®ãã®ã¹ã¬ããã¯ã«ãŒãã§åŸ æ©ããŸãïŒäžæçã«ã¹ãªãŒãç¶æ ã«ãªãå¯èœæ§ããããŸãïŒã æåã®ã¹ã¬ãããããã¯ã解æŸãããšãããã»ããµã¯æ¬¡ã®åŸ æ©ã¹ã¬ããã®ã©ããããã¯ãååŸãããã決å®ããŸãã ãªã©ãªã©ã
æå³ãåã2ã€ã®äŸã次ã«ç€ºããŸãã
- std :: atomic_flagã䜿çšïŒ[19] coliru.stacked-crooked.com/a/1ec9a0c2b10ce864
- std :: atomic <int>ã䜿çšïŒ[20] coliru.stacked-crooked.com/a/03c019596b65199a
äŸ1ãæãŸãããããã¡ã¢ãªããªã¢ã䜿çšããæå³ãæŠç¥çã«ç€ºããŠããŸããååæäœã¯éäžè²ã§ç€ºãããŠããŸãã
[19] coliru.stacked-crooked.com/a/1ec9a0c2b10ce864
ããªã¢ã®æå³ã¯éåžžã«åçŽã§ã-ã³ã³ãã€ã©ãŒãªããã£ãã€ã¶ãŒã¯ãåœä»€ãã¯ãªãã£ã«ã«ã»ã¯ã·ã§ã³ããå€éšã«ç§»åããããšãèš±å¯ãããŠããŸããã
- memory_order_ acquireã®åŸã«ããåœä»€ã¯ããã®åã«å®è¡ã§ããŸããã
- memory_order_ releaseã®åã«ããåœä»€ã¯ãããããåŸã«å®è¡ããããšã¯ã§ããŸããã
ããã©ãŒãã³ã¹ãæé©åããããã«ãã³ã³ãã€ã©ãŒïŒã³ã³ãã€ã«æïŒãŸãã¯ããã»ããµãŒïŒã©ã³ã¿ã€ã ïŒã«ãã£ãŠãç¬ç«ããåœä»€ã®å®è¡é åºã®ãã®ä»ã®å€æŽãå®è¡ã§ããŸãã
ããšãã°ãæååint new_shared_value = shared_value; lock_flag.clearïŒstd :: memory_order_releaseïŒã®åã«å®è¡ã§ããŸãã ã ãã®äžŠã¹æ¿ãã¯èš±å®¹ãããããŒã¿ç«¶åãäœæããŸããã è€æ°ã®ã¹ããªãŒã ã«å ±éã®ããŒã¿ã«ã¢ã¯ã»ã¹ãããã¹ãŠã®ã³ãŒãã¯ãåžžã«2ã€ã®ååŸããã³è§£æŸããªã¢ã«å²ãŸããŠããŸãã å€éšã«ã¯ãã¹ããªãŒã ã®ããŒã«ã«ããŒã¿ã§ã®ã¿æ©èœããã³ãŒãããããŸããå®è¡ãããé åºã¯é¢ä¿ãããŸããã ã¹ã¬ããã«ããŒã«ã«ãªäŸåé¢ä¿ã¯ãã·ã³ã°ã«ã¹ã¬ããå®è¡ã®å Žåãšåãæ¹æ³ã§åžžã«ä¿æãããããã int new_shared_value = shared_value; shared_value + = 25ããåã«å®è¡ããããšã¯ã§ããŸããã
çŠæ¢ãããŠãããã®ãšãååŸ-解æŸã®éå£ãã¯ãªãã£ã«ã«ã»ã¯ã·ã§ã³ãèš±å¯ãããã®ã¯äœã§ããïŒ
- ã¯ãªãã£ã«ã«ã»ã¯ã·ã§ã³ã®å éšã«ããæäœã¯ãã¯ãªãã£ã«ã«ã»ã¯ã·ã§ã³ã®å€éšã§å®è¡ã§ããŸããã
- ã¯ãªãã£ã«ã«ã»ã¯ã·ã§ã³å€ã®æäœã¯ãã¯ãªãã£ã«ã«ã»ã¯ã·ã§ã³å ã§å®è¡ã§ããŸãïŒè¿œå ã®ã¡ã¢ãªããªã¢ããªãå ŽåïŒã
std :: memory_orderã§ã³ã³ãã€ã©ãå®è¡ããç¹å®ã®ã¢ã¯ã·ã§ã³ïŒ
- 1ã6ïŒã³ã³ãã€ã©ãŒã¯ãç¹å®ã®ããã»ããµãŒã»ã¢ãŒããã¯ãã£ãŒã«ãããã®ããªã¢ãŒãå¿ èŠãªå ŽåãããŒãæäœã®ååŸããªã¢ãŒãšã¹ãã¢æäœã®ãªãªãŒã¹ããªã¢ãŒã®ã¢ã»ã³ãã©ãŒåœä»€ãçæããŸãã
- 2 ïŒã³ã³ãã€ã©ã¯ãå¥ã®ã¹ã¬ããã«ãã£ãŠå€æŽããããããã®å€æ°ã®å€ãåããŒãããããã«ãããã»ããµã¬ãžã¹ã¿ã®å€æ°ã®ä»¥åã®ãã£ãã·ã¥ããã£ã³ã»ã«ããŸã-ããŒãïŒååŸïŒæäœåŸ
- 5 ïŒã³ã³ãã€ã©ã¯ããã¹ãŠã®å€æ°ã®å€ãããã»ããµã¬ãžã¹ã¿ããã¡ã¢ãªã«ä¿åããŠãä»ã®ã¹ã¬ããããèŠããããã«ããŸãã ããŒããïŒ ãªã³ã¯ ïŒ-ã¹ãã¢ïŒãªãªãŒã¹ïŒã®å
- 3ã4 ïŒã³ã³ãã€ã©ãŒã¯ããªããã£ãã€ã¶ãŒãçŠæ¢ãããæ¹åã«åœä»€ã䞊ã¹æ¿ããããšãé²ããŸã-èµ€ãç¢å°ã§ç€ºãããŠããŸã
次ã«ãAcquire-Releaseã®ä»£ããã«Relaxed-Releaseã»ãã³ãã£ã¯ã¹ã䜿çšããå Žåã«äœãèµ·ããããèŠãŠã¿ãŸãããã
- å·Šãžã Acquire-Releaseã®å Žåããã¹ãŠãæ£ããå®è¡ãããŸãã
- å³ãžã Relaxed-Releaseã®å Žåãã¢ã«ãŽãªãºã ã¯æ¬¡ã®ããã«æ£ããåäœããŸããã ããã¯ã«ãã£ãŠä¿è·ãããŠããã¯ãªãã£ã«ã«ã»ã¯ã·ã§ã³å ã®ã³ãŒãã®äžéšã¯ãã³ã³ãã€ã©ãŸãã¯ããã»ããµã«ãã£ãŠå€åŽã«ç§»åã§ããŸãã ãã®åŸãããŒã¿ç«¶åã®åé¡ãçºçããŸã-ããã¯åã§ãã£ãŠããå€ãã®ã¹ã¬ãããéã¢ãããã¯æäœãå®è¡ãããããŒã¿ãšåæã«åäœãéå§ããŸã-誀ã£ãçµæãåŸãããšãã§ããŸãã
ã¢ãããã¯æäœã®å©ããåããŠã®ã¿ãäžè¬çãªããŒã¿ãä»ããŠãã¹ãŠã®ããžãã¯ãå®è£ ããããšã¯éåžžäžå¯èœã§ããããšã«æ³šæããŠãã ããããããã£ãŠãããã·ã³ãã«ã§é«éã§ãã1ã€ã®ã¢ãããã¯æäœã§ããã©ã°ãclosedããèšå®ãããããŒã«å ±éã®ããŒã¿ã§ãã¹ãŠã®éã¢ãããã¯æäœãå®è¡ãããã©ã°ãopenããèšå®ããŸãã
ãã®ããã»ã¹ãæéçã«æŠç¥çã«ç€ºããŸã
ãããšãã°ã2ã€ã®ã¹ã¬ãããadd_to_sharedïŒïŒé¢æ°ã®å®è¡ãéå§ããŸãã
- ã¹ã¬ãã1ã¯å°ãæ©ãå ¥ãã1ã€ã®ã¢ãããã¯åœä»€test_and_setïŒïŒã§äžåºŠã«2ã€ã®æäœãå®è¡ããŸãïŒlock_flag == falseãã©ããããã§ãã¯ããtrueã«èšå®ïŒã€ãŸããã¹ãã³ããã¯ããããã¯ïŒããfalseãè¿ããŸãããããã£ãŠãåŒwhileïŒlock_flag.test_and_setïŒïŒïŒ; ã¯ãªãã£ã«ã«ã»ã¯ã·ã§ã³ã³ãŒãã¯ããã«çµäºããå®è¡ãéå§ããŸãã
- çŸæç¹ã§ã¹ã¬ãã2ã¯ããã®ã¢ãããã¯ãªtest_and_setïŒïŒåœä»€ã®å®è¡ãéå§ããŸããlock_flag== falseã§ãããã©ããã確èªããtrueã«èšå®ããŸãããããã£ãŠãåŒwhileïŒlock_flag.test_and_setïŒïŒïŒ; whileïŒlock_flagïŒãŸã§å®è¡ãããŸã;
- ã¹ã¬ãã1ã¯ãå ç®æäœshared_value + = 25ãå®è¡ããŸãããããŠãã¢ãããã¯æäœã«ãã£ãŠå€lock_flag = falseãèšå®ããŸãïŒã€ãŸããã¹ãã³ããã¯ã解é€ããŸãïŒã
- ã¹ã¬ãã2ãæåŸã«æ¡ä»¶lock_flag == falseãåŸ ã£ãŠãlock_flag = trueãå²ãåœãŠãfalseãè¿ããã«ãŒããçµäºããŸãã次ã«ãshared_value + = 25ãè¿œå ããŸãããŸããlock_flag = falseïŒã¹ãã³ããã¯ã®ããã¯è§£é€ïŒãå²ãåœãŠãŸãã
ãã®ç« ã®åé ã§ã2ã€ã®äŸãæããŸããã
- std :: atomic_flagããã³test_and_setïŒïŒã䜿çšïŒ[21] coliru.stacked-crooked.com/a/1ec9a0c2b10ce864
- std :: atomic <int>ããã³compare_exchange_weakïŒïŒã䜿çšïŒ[22] coliru.stacked-crooked.com/a/03c019596b65199a
ãããã®æäœã®è©³çŽ°ã«ã€ããŠã¯ããªã³ã¯ãã芧ãã ãããen.cppreference.com / w / cpp / atomic / atomic
GCCã³ã³ãã€ã©ãŒã«ãã£ãŠçæãããx86_64ã®ã¢ã»ã³ãã©ãŒã³ãŒãããããã2ã€ã®äŸã§ã©ã®ããã«ç°ãªãããèŠãŠã¿ãŸããã
ã䟿å®äžã1ã€ã®ã¯ã©ã¹ã«çµåã§ããŸãã
class spinlock_t { std::atomic_flag lock_flag; public: spinlock_t() { lock_flag.clear(); } bool try_lock() { return !lock_flag.test_and_set(std::memory_order_acquire); } void lock() { for (size_t i = 0; !try_lock(); ++i) if (i % 100 == 0) std::this_thread::yield(); } void unlock() { lock_flag.clear(std::memory_order_release); } };
ã¯ã©ã¹ã®äœ¿çšäŸã¯ãspinlock_t次ã®ãªã³ã¯ãïŒ[23] coliru.stacked-crooked.com/a/92b8b9a89115f080
ããªããéå£ã®çš®é¡ã䜿çšãããšãããx86_64çã§ã³ã³ãã€ã«ãããŸããç§ã¯æ¬¡ã®è¡šãäžããç解ããããšã¯ã§ããŸãã決ããŠããšã確èªããŸãã
ç»åããã«ãµã€ãºã§è¡šç€ºããããšãã§ããŸããªã³ã¯ããã©ããŸãïŒhsto.org/files/4f8/7b4/1b6/4f87b41b64a54549afca679af1028f84.jpg
ã³ã³ãã€ã©ãæé©åã®ããã«ã¢ã»ã³ãã©åœä»€ã亀æã§ããªãå Žåã«ã¢ã»ã³ãã©x86_64ã§ã³ãŒããèšè¿°ããŠããå Žåã«ã®ã¿ã以äžãç¥ãå¿ èŠããããŸãã
- seq_cst . (Clang MSVC) GCC â Store Sequential Consistency, : a.store(val, memory_order_seq_cst); â Clang MSVC [LOCK] XCHG reg, [addr], CPU-Store-buffer , MFENCE. GCC MOV [addr], reg MFENCE.
- RMW (CAS, ADDâŠ) always seq_cst . ãªããªã RMW (Read-Modify-Write) x86_64 LOCK, Store-Buffer, Sequential-Consistency . memory_order RMW , memory_order_acq_rel.
- LOAD(acquire), STORE(release) . , x86_64 4 (relaxed, consume, acquire, release) â .. x86_64 acquire-release â - MESIF(Intel) / MOESI (AMD). Write Back ( , Un-cacheable Write Combined â Mapped Memory Area from Device â Acquire-semantic).
ç§ãã¡ãç¥ã£ãŠããããã«ãäŸåããæäœã¯ã©ãã§ã䞊ã¹æ¿ããããšã¯ã§ããŸãããããšãã°ãïŒRead-XãWrite-XïŒãŸãã¯ïŒWrite-XãRead-XïŒ
x86_64ã®Herb Sutterã®ããã©ãŒãã³ã¹ããã®ã¹ã©ã€ãïŒhttps : //onedrive.liveã com / view.aspxïŒresid = 4E86B0CF20EF15ADïŒ24884ïŒapp = WordPdfïŒauthkey =ïŒAMtj_EflYn2507c
â¢x86_64ã§ã¯é åºãå€æŽã§ããŸããã
- èªã¿åãX-èªã¿åãY
- èªã¿åãX-æžã蟌ã¿Y
- æžã蟌ã¿X-æžã蟌ã¿Y
â¢x86_64ã§ã¯ãä»»æã®é åºãå€æŽã§ããŸãïŒWrite-X <â> Read-Yããããé²ãããã«ãstd :: memory_order_seq_cstããªã¢ã䜿çšãããŸããããã¯ãã³ã³ãã€ã©ã«å¿ããŠ4ã€ã®ããŒãžã§ã³ã®x86_64ã³ãŒããçæã§ããŸãã
- ããŒãïŒMOVïŒã¡ã¢ãªããïŒã¹ãã¢ïŒMOVïŒã¡ã¢ãªãžïŒãMFENCE
- ããŒãïŒMOVïŒã¡ã¢ãªããïŒã¹ãã¢ïŒLOCK XCHGïŒã¡ã¢ãªãžïŒ
- ããŒãïŒMFENCE + MOVïŒã¡ã¢ãªããïŒã¹ãã¢ïŒMOVïŒã¡ã¢ãªãžïŒ
- ããŒãïŒLOCK XADDïŒ0ãã¡ã¢ãªããïŒã¹ãã¢ïŒMOVïŒã¡ã¢ãªãžïŒ
ã¢ãŒããã¯ãã£ãŒïŒx86_64ãPowerPCãARMv7ãARMv8ãAArc64ãItaniumïŒã®ããã»ããµãŒåœä»€ãšã¡ã¢ãªãŒããªã¢ãŒã®ã³ã³ãã©ã€ã¢ã³ã¹ã®æŠèŠè¡šïŒwww.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html
ããŸããŸãªã³ã³ãã€ã©ãŒã®å®éã®ã¢ã»ã³ãã©ãŒã³ãŒãã衚瀺ãªã³ã¯ããã©ãããšãã§ããŸãããŸããARMãARM64ãAVRãPowerPCãªã©ã®ä»ã®ã¢ãŒããã¯ãã£ãéžæã§ããŸãã
GCC 6.1ïŒx86_64ïŒïŒ
- ããŒã/ã¹ãã¢ïŒgodbolt.org/g/xq9ulH
- RMWïŒfetch_addïŒïŒgodbolt.org/g/dp1zZ0
- CASïŒcompare_exchange_weakïŒïŒ/ compare_exchange_strongïŒïŒïŒïŒgodbolt.org/g/OMuXmz
- std :: atomic_flag :: test_and_setïŒïŒïŒgodbolt.org/g/7ksl0J
Clang 3.8ïŒx86_64ïŒïŒ
- ããŒã/ã¹ãã¢ïŒgodbolt.org/g/gfpeZW
- RMWïŒfetch_addïŒïŒgodbolt.org/g/afoIQW
- CASïŒcompare_exchange_weakïŒïŒ/ compare_exchange_strongïŒïŒïŒïŒgodbolt.org/g/kYXzK6
- std :: atomic_flag :: test_and_setïŒïŒïŒgodbolt.org/g/RD5fJG
ãŸããCASïŒCompare-and-swapïŒåœä»€ã®é åºã«ããŸããŸãªã¡ã¢ãªããªã¢ãåãŒã圱é¿ãè¡šã«ç°¡åã«ç€ºããŸããen.cppreference.com / w / cpp / atomic / atomic / compare_exchange
ã¡ã¢ãªã¢ã¯ã»ã¹æäœã®äžŠã¹æ¿ãã®äŸ
次ã«ã4ã€ã®é£ç¶ããæäœïŒLOADãSTOREãLOADãSTOREïŒããã®äžŠã¹æ¿ãã®ããè€éãªäŸã瀺ããŸãã
- éãé·æ¹åœ¢ã¯ã¢ãããã¯æäœã§ãã
- æããéè²ã®å åŽã®æãéè²ã®åè§åœ¢ïŒäŸ3ããã³4ïŒã¯ãè€æ°ã®ã¢ãããã¯æäœã§æ§æãããè€åã¢ãããã¯èªã¿åã-å€æŽ-æžã蟌ã¿ïŒRMWïŒåœä»€ã®äžéšã§ãã
- çœãé·æ¹åœ¢ã¯ãéåžžã®éååæäœã§ãã
ã¢ãããã¯å€æ°ã䜿çšããæäœã®åšãã«ãéåžžã®å€æ°ã䜿çšããæäœã®å¯èœãªäžŠã¹æ¿ãã瀺ã4ã€ã®äŸããããã瀺ããŸãããã ããäŸ1ããã³3ã®ã¿ã§ãã¢ãããã¯æäœã䞊ã¹æ¿ããããšãå¯èœã§ãã
æåã®ã±ãŒã¹ã¯ãããã€ãã®ã¯ãªãã£ã«ã«ã»ã¯ã·ã§ã³ã1ã€ã«èåã§ãããšããç¹ã§èå³æ·±ããã®ã§ãã
ã³ã³ãã€ã©ã¯ã³ã³ãã€ã«æã«ãã®ãããªäžŠã¹æ¿ããå®è¡ã§ããŸããããã³ã³ãã€ã©ã¯å®è¡æã«ããã»ããµããã®äžŠã¹æ¿ããå®è¡ã§ããããã«ããŸãããããã£ãŠãç°ãªãã¹ã¬ããã®ç°ãªãã·ãŒã±ã³ã¹ã§å®è¡ãããã¯ãªãã£ã«ã«ã»ã¯ã·ã§ã³ã®ããŒãžã¯ãæåã®åœä»€ã·ãŒã±ã³ã¹ãããã»ããµã«è¡šç€ºãããããããããããã¯ã«ã€ãªããããšã¯ãããŸããããããã£ãŠãããã»ããµã¯äºåã«2çªç®ã®ã¯ãªãã£ã«ã«ã»ã¯ã·ã§ã³ã«å ¥ãããã«è©Šã¿ãŸãããã§ããªãå Žåã¯ãæåã®ã¯ãªãã£ã«ã«ã»ã¯ã·ã§ã³ã®å®è¡ãç¶ç¶ããå®å šã«å®äºããåŸã2çªç®ã®ã¯ãªãã£ã«ã«ã»ã¯ã·ã§ã³ã«å ¥ãã®ãåŸ ã¡ãŸãã
3çªç®ã®ã±ãŒã¹ã¯ã2ã€ã®è€åã¢ãããã¯åœä»€ã®äžéšã䞊ã¹æ¿ããããšãã§ãããšããç¹ã§èå³æ·±ãïŒSTORE A <-> LOAD B.
- , 3- ASM- (lwarx, add, stwcx), LL/SC ( wiki-link ), : godbolt.org/g/j8uw7n , .
2çªç®ã®ã±ãŒã¹ã¯ãstd :: memory_order_seq_cstãæã匷åãªéå£ã§ãããããèªäœã®ã¢ãããã¯ãŸãã¯éã¢ãããã¯æäœã®äžŠã¹æ¿ããçŠæ¢ããŠããããã«èŠãããšããç¹ã§èå³æ·±ããã®ã§ãããã ããseq_cstããªã¢ã«ã¯ãååŸ/解æŸãšæ¯èŒããŠ1ã€ã®è¿œå ããããã£ãããããŸãããäž¡æ¹ã®ã¢ãããã¯æäœã«seq_cstããªã¢ãããå Žåã®ã¿ãæäœã®ã·ãŒã±ã³ã¹ã¯STORE-AïŒseq_cstïŒã§ããLOAD-BïŒseq_cstïŒ; 䞊ã¹æ¿ããããšã¯ã§ããŸãããC ++æšæºããã®2ã€ã®åŒçšç¬Šã次ã«ç€ºããŸãã
- å³å¯ã§åäžãªçžäºå®è¡é åºã¯ãmemory_order_seq_cstããªã¢ãStandard C ++ 11§29.3ïŒ3ïŒã䜿çšããæäœã«å¯ŸããŠã®ã¿ä¿æãããŸãïŒwww.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4606.pdf
There shall be a single total order S on all memory_order_seq_cst operations , consistent with the âhappens beforeâ order and modification orders for all affected locations, such that each memory_order_seq_cst operation B that loads a value from an atomic object M observes one of the following values: âŠ
- memory_order_seq_cst memory_order_seq_cstâ , Standard C++11 § 29.3 (8): www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4606.pdf
[泚ïŒmemory_order_seq_cstã¯ãããŒã¿ã®ç«¶åããªããmemory_order_seq_cstæäœã®ã¿ã䜿çšããããã°ã©ã ã«å¯ŸããŠã®ã¿ãé 次æŽåæ§ãä¿èšŒããŸãã匱ãé åºä»ãã䜿çšãããšã现å¿ã®æ³šæãæããªãéãããã®ä¿èšŒã¯ç¡å¹ã«ãªããŸããç¹ã«ãmemory_order_seq_cstãã§ã³ã¹ã¯ããã§ã³ã¹èªäœã«å¯ŸããŠã®ã¿å®å šãªé åºãä¿èšŒããŸããäžè¬ã«ããã§ã³ã¹ã䜿çšããŠãé åºä»ãä»æ§ããã匱ãã¢ãããã¯æäœã®é 次äžè²«æ§ã埩å ããããšã¯ã§ããŸããã-çµäºããŒã]
seq_cstæäœãäžå¿ã«éseq_cstæäœïŒã¢ãããã¯ããã³éã¢ãããã¯ïŒã䞊ã¹æ¿ããããã«èš±å¯ãããŠããæ瀺ã¯ãååŸ/解æŸãšåãã§ãã
- a.loadïŒmemory_order_seq_cstïŒ -ãšåãé åºã§ã¯ãªãseq_cstãªãã¬ãŒã·ã§ã³ãä¿èšŒããa.loadïŒmemory_order_acquireïŒ
- b.storeïŒmemory_order_seq_cstïŒ -ãšåãé åºã§ã¯ãªãseq_cstãªãã¬ãŒã·ã§ã³ãä¿èšŒããb.storeïŒmemory_order_releaseïŒ
ããå³å¯ãªé åºãå¯èœã§ãããä¿èšŒãããŠããŸããã
seq_cstã®å Žåãããã³ååŸãšè§£æŸã®å ŽåïŒSTOREïŒseq_cstïŒã®åã«ã¯äœãã§ãããLOADïŒseq_cstïŒã®åã«ã¯äœãã§ããŸããã
ããããéæ¹åã§ã¯äžŠã¹æ¿ããå¯èœã§ãã
次ã«ãã³ã³ãã€ã©ãŒãããã»ããµãŒã«èš±å¯ããåœä»€ã®é åºã®å€æŽãããšãã°x86_64ããã³PowerPCã®GCC-ã¢ã»ã³ãã©ãŒx86_64ããã³PowerPCã®C ++ã³ãŒããšçæã³ãŒãã®äŸã瀺ããŸãã
memory_order_seq_cst âæäœã®ååŸã§ã次ã®é åºå€æŽãå¯èœã§ãã
- x86_64 Store-Load. ã€ãŸã :
STORE-C(release); LOAD-B(seq_cst); ==> LOAD-B(seq_cst); STORE-C(release);
ãªããªã x86_64, MFENCE STORE(seq_cst), LOAD(seq_cst) LOAD(release) LOAD(relaxed): godbolt.org/g/BsLqas - PowerPC Store-Load, Store-Store . ã€ãŸã :
STORE-A(seq_cst); STORE-C(relaxed); LOAD-C(relaxed); ==>
ãªããªãPowerPCã¢ãŒããã¯ãã£ã§ã¯ãseq_cstããªã¢ã®å ŽåãsyncïŒhwsyncïŒã¯STOREïŒseq_cstïŒããã³LOADïŒseq_cstïŒã«ã®ã¿è¿œå ããããããSTOREïŒseq_cstïŒãšLOADïŒseq_cstïŒã®éã«ãããã¹ãŠã®åœä»€ã¯STOREïŒseq_cstïŒã®åã«å®è¡ã§ããŸãïŒgodbolt.org/g/dm7tWd
LOAD-C(relaxed); STORE-C(relaxed); STORE-A(seq_cst);
ã»ãã³ãã£ã¯ã¹ãæã€3ã€ã®å€æ°ã®äŸãseq_cstããã³relaxedããã詳现ã«ç€ºããŸãã
C ++ã³ã³ãã€ã©ãã§ãã䞊ã¹æ¿ã
- PowerPCçšC ++ããASMïŒgodbolt.org/g/mEM8T8
- C ++ããASM for x86_64ïŒgodbolt.org/g/lTNMJ2
ãªããã®ãããªæ³šæå€æŽãå¯èœã§ããïŒC ++ã³ã³ãã€ã©ã¯x86_64ããã»ããµãšPowerPCããã»ããµã®ãã®ãããªäžŠã¹æ¿ããå¯èœã«ããã¢ã»ã³ãã©ã³ãŒããçæããããã
åœä»€éã«ã¢ã»ã³ãã©ããªã¢ããªãå ŽåãããŸããŸãªCPUã¯äžŠã¹æ¿ããå®è¡ã§ããŸãããã¡ã¢ãªããªã¢ïŒãœãããŠã§ã¢ããã«ãŒã®ããŒããŠã§ã¢ãã¥ãŒãPaul E. McKenney 2010幎6æ7æ¥-è¡š5ïŒwww.rdrop.com/users/paulmck/scalability/paper/whymb.2010.06.07c.pdf
ããŒã¿äº€æã«ã¯å¥ã®æ©èœããããŸãã¹ã¬ããéã4ã¹ã¬ãã以äžã®çžäºäœçšã§çŸããŸãã次ã®æäœã®å°ãªããšã1ã€ãæãå³ããããªã¢memory_order_seq_cstã䜿çšããªãå Žåãç°ãªãã¹ã¬ããã¯åãå€æŽãç°ãªãé åºã§èŠãããšãã§ããŸããäŸïŒ
- ã¹ã¬ãã1ãæåã«å€ãå€æŽããå Žå
- -2
- -3 -2, -1
- -4 -1, -2
ããã¯ããã£ãã·ã¥ã³ããŒã¬ã³ããããã³ã«ã®ããŒããŠã§ã¢æ©èœãè¿œå ã®ããŒã/ã¹ãã¢ãããã¡ãããã³ããã»ããµå ã®ã³ã¢ã®å Žæã®ããããžã«ããå¯èœã§ãããã®å Žåãããã€ãã®2ã€ã®ã«ãŒãã«ã¯ãä»ã®ã«ãŒãã«ã«ãã£ãŠè¡ãããå€æŽãèŠãåã«ãäºãã«è¡ãããå€æŽãèŠãããšãã§ããŸãããã¹ãŠã®ã¹ã¬ãããåãé åºã§å€æŽãèªèããããã«ãã€ãŸããã£åå šé åºïŒC ++ 11§29.3ïŒ3ïŒïŒ -ãã¹ãŠã®æäœïŒããŒããã¹ãã¢ãRMWïŒã¯ãã¡ã¢ãªããªã¢memory_order_seq_cstäžã§å®è¡ããããšãå¿ èŠã§ããïŒen.cppreference.com/w/cpp/atomic/memory_order
以äžã®äŸã§ã¯ãããã°ã©ã ã¢ãµãŒããšã©ãŒïŒz.loadïŒïŒïŒ= 0ïŒã§å€±æããããšã¯ãããŸããããªããªããã¹ãŠã®æäœã¯ãæãå³ããã¡ã¢ãªããªã¢memory_order_seq_cstãé©çšãããŸããcoliru.stacked-crooked.com/a/52726a5ad01f6529
å³ã¯ãé åºã®å€æŽãã·ãŒã±ã³ã·ã£ã«ã®ããã«ç²åŸ-ãªãªãŒã¹ã»ãã³ãã£ã¯ã¹ãšã»ãã³ãã£ã¯ã¹-EH 4ã¹ããªãŒã ã®äŸã«ã€ããŠã¯ãå¯èœã§ããããšã瀺ããŸãã
- Acuire-ReleaseïŒ
â¢éåžžã®å€æ°ã®é åºãèš±å¯ãããæ¹å
ã«å€æŽããããšãã§ããŸããâ¢Acquire-Releaseã»ãã³ãã£ã¯ã¹ã§ã¢ãããã¯å€æ°ã®é åºãå€æŽããããšãã§ããŸãã - ã·ãŒã±ã³ã·ã£ã«ïŒ
â¢èš±å¯ãããæ¹åã§éåžžã®å€æ°ã®é åºãå€æŽããããšã¯å¯èœã§ãã⢠ã·ãŒã±ã³ã·ã£ã«ã»ãã³ãã£ã¯ã¹ã§ã¢ãããã¯å€æ°ã®é åºãå€æŽããããšã¯ã§ããŸãã
ã
ã¢ã¯ãã£ãã¹ãã³ããã¯ãšååž°çã¹ãã³ããã¯
ç¬èªã®ã¢ã¯ãã£ãããã¯ïŒã¹ãã³ããã¯ãšååž°çã¹ãã³ããã¯ïŒãå®è£ ããäŸã«ãããã¢ãããã¯æäœã§ã¡ã¢ãªããªã¢ãã©ã®ããã«äœ¿çšããããã瀺ããŸãã
ããã«ãããŒãã«å šäœïŒããŒãã«ããã¯ïŒãããã¯ããã®ã§ã¯ãªããããŒãã«ã®åã ã®è¡ïŒè¡ããã¯ïŒãããã¯ããããã«ãããã®ããã¯ãå¿ èŠã«ãªããŸããããã«ããã䞊å床ãåäžããããã©ãŒãã³ã¹ãåäžããŸããç°ãªãã¹ã¬ããã¯ãããŒãã«å šäœããããã¯ããããšãªããç°ãªãè¡ã䞊è¡ããŠåŠçã§ããŸãã
ãªãã¬ãŒãã£ã³ã°ã·ã¹ãã ã«ãã£ãŠæäŸãããåæãªããžã§ã¯ãã®æ°ã¯å¶éãããå ŽåããããŸããããŒãã«å ã®è¡ã®æ°ã¯æ°çŸäžãŸãã¯æ°ååã«ãªãå¯èœæ§ããããå€ãã®ãªãã¬ãŒãã£ã³ã°ã·ã¹ãã ã§ã¯ããã»ã©å€ãã®ãã¥ãŒããã¯ã¹ãäœæã§ããŸããããŸããã¹ãã³ããã¯ã®æ°ã¯RAMãèš±ãéãããã€ã§ãæ§ããŸããããããã£ãŠãåã ã®è¡ããããã¯ããããã«äœ¿çšã§ããŸãã
å®éãã¹ãã³ããã¯ã¯åè¡ã«+ 1ãã€ãããŸãã¯ååž°ã¹ãã³ããã¯ã䜿çšããå Žåã¯+17ãã€ãã§ãïŒãã©ã°ã«1ãã€ã+ååž°ã«ãŠã³ã¿ãŒã«8ãã€ã+ thread_idã¹ã¬ããçªå·ã«8ãã€ãïŒã
- ã¹ãã³ããã¯ã®å®è£ ãšäœ¿çšã®äŸãæ¢ã«ç€ºããŠããŸãïŒ[24] coliru.stacked-crooked.com/a/92b8b9a89115f080
- 次ã«ãrecursive_spinlockã®å®è£ ãšäœ¿çšã®äŸã瀺ããŸãã[25] coliru.stacked-crooked.com/a/eae6b7da971810a3
recursive_spinlockãšéåžžã®ã¹ãã³ããã¯ã®äž»ãªéãã¯ãåãã¹ã¬ããã«ãã£ãŠrecursive_spinlockãäœåºŠããããã¯ã§ããããšã§ããååž°çãªãã¹ããããããã¯ããµããŒãããŸããåæ§ã«ãstd :: recursive_mutexãšstd :: mutexã¯ç°ãªããŸãã
ãã¹ããããããã¯ã®äŸïŒ
- spinlock_t â (deadlock) â : [26] coliru.stacked-crooked.com/a/d3b93315270fd367
- recursive_spinlock_t â â shared_value = 50: [27] coliru.stacked-crooked.com/a/875ad2754a007037
recursive_spinlock_tã®ä»çµã¿ãèŠãŠã¿ãŸãããã
MSVC 2013ã³ã³ãã€ã©ã§ãã®ã³ãŒããå®è¡ããããšãããšãstd :: this_thread :: get_idïŒïŒfunctionïŒconnect.microsoft.com/VisualStudio/feedback/details/1558211ã® ããã«éåžžã«åŒ·åãªã¹ããŒããŠã³ãçºçããŸããrecursive_spinlock_t
ã¯ã©ã¹ããã¡ã€ãã©ã€ãºããŠã __declspecïŒã¹ã¬ããïŒå€æ°ã®ãã£ãã·ã¥ãããthread-idã¯ãC ++ 11æšæºã®thread_localã«é¡äŒŒããŠããŸãããã®äŸã¯MSVC 2013ã§ãè¯å¥œãªããã©ãŒãã³ã¹ã瀺ããŸãã[28] coliru.stacked-crooked.com/a/3090a9778d02f6ea
ããã¯å€ãMSVC 2013ã®äžæçãªä¿®æ£ã§ããããããã®ãããªãœãªã¥ãŒã·ã§ã³ã®çŸããã«ã€ããŠã¯èããŸããã
ã»ãšãã©ã®å Žåãmutexã®ç¹°ãè¿ãïŒååž°çïŒãããã¯ã¯èšèšãšã©ãŒã§ãããšèããããŠããŸãããä»åã®å Žåãé ããåäœããã³ãŒãã§ããå¯èœæ§ããããŸãã第äºã«ã誰ããééã£ãŠãããååž°ããã¯ãåã蟌ãŸããŠãããããrecursive_spinlock_tã¯ãã£ãšé ããªããspinlock_tã¯æ°žä¹ ã«ãã³ã°ã¢ããããŸãã
ã¹ã¬ããã»ãŒãsafe_ptr <T>ã䜿çšããå Žåãäž¡æ¹ã®äŸã¯éåžžã«è«ççã§ããã2çªç®ã®äŸã¯recursive_spinlockã§ã®ã¿æ©èœããŸãã
safe_int_spin_recursive->second++; // spinlock & recursive_spinlock safe_int_spin_recursive->second = safe_int_spin->second + 1; // only recursive_spinlock
ç¬èªã®é«æ§èœå ±æãã¥ãŒããã¯ã¹ã®å®è£
ãåç¥ã®ããã«ãæ°ããã¿ã€ãã®ãã¥ãŒããã¯ã¹ãæ°ããC ++æšæºã«åŸã ã«ç»å ŽããŸããïŒen.cppreference.com/w/cpp/thread
- C ++ 11ïŒmutexãtimed_mutexãrecursive_mutexãrecursive_timed_mutex
- C ++ 14ïŒshared_timed_mutex
- C ++ 17ïŒshared_mutex
shared_mutexã¯ããã®æç¹ã§ãã®ããŒã¿ãå€æŽããã¹ã¬ãããååšããªãå Žåãå€ãã®ã¹ã¬ãããåãããŒã¿ãåæã«èªã¿åãããšãã§ãããã¥ãŒããã¯ã¹ã§ãã shared_mutexã¯ããã«ã¯è¡šç€ºãããŸããã§ãããéåžžã®std :: mutexãšæ¯èŒããããã©ãŒãã³ã¹ã«ã€ããŠã¯è°è«ããããŸããã
ãªãŒããŒã®æ°ã®ã«ãŠã³ã¿ãŒã䜿çšããshared_mutexã®å€å žçãªå®è£ ã¯ãå€ãã®ãªãŒããŒãé·æéããã¯ãä¿æããŠããå Žåã«ã®ã¿é床ã®å©ç¹ã瀺ããŸãã-ã€ãŸã圌ããé·ãéèªãã ãšãçãèªã¿åãã§ã¯ãshared_mutexã¯ããã°ã©ã ã®é床ãäœäžãããã³ãŒããè€éã«ããã ãã§ãã
ãããããã¹ãŠã®shared_mutexå®è£ ã¯çãèªã¿åãã§éåžžã«é ãã®ã§ããããïŒ
std :: shared_mutexããã³boost :: shared_mutexã®åäœãé ãäž»ãªçç±ã¯ãã¢ãããã¯ãªãŒããŒã«ãŠã³ã¿ãŒã§ããåèªã¿åãã¹ããªãŒã ã¯ããããã¯ããããšã«ãŠã³ã¿ãŒãã€ã³ã¯ãªã¡ã³ãããããã¯ã解é€ããããšã«ãŠã³ã¿ãŒããã¯ãªã¡ã³ãããŸãããã®çµæãã¹ã¬ããã¯ã³ã¢éã®1ã€ã®ãã£ãã·ã¥ã©ã€ã³ãåžžã«é§åããŸãïŒã€ãŸããæä»ç¶æ ïŒEïŒãé§åããŸãïŒããã®ãããªå®è£ ã®ããžãã¯ã«ããã°ãåèªã¿åãã¹ããªãŒã ã¯çŸåšã®ãªãŒããŒã®æ°ãã«ãŠã³ãããŸãããããã¯èªã¿åãã¹ããªãŒã ã«ãšã£ãŠçµ¶å¯Ÿã«éèŠã§ã¯ãããŸããã圌ã«ãšã£ãŠéèŠãªã®ã¯ãäžäººã®äœå®¶ãããã¹ãã§ã¯ãªããšããããšã§ãããŸããã€ã³ã¯ãªã¡ã³ããšãã¯ãªã¡ã³ãã¯RMWæäœã§ãããåžžã«ã¹ãã¢ãããã¡ã¯ãªãŒã³ã¢ããïŒMFENCE x86_64ïŒãçæããx86_64 asmã¬ãã«ã§ã·ãŒã±ã³ã·ã£ã«æŽåæ§ã®æãé ãã»ãã³ãã£ã¯ã¹ã«å®éã«å¯Ÿå¿ããŸãã
ãã®åé¡ã解決ããŠã¿ãŸãããã
競åã®ãªãæžã蟌ã¿ãšããŠåé¡ãããã¿ã€ãã®ã¢ã«ãŽãªãºã ããããŸã-è€æ°ã®ã¹ããªãŒã ãæžã蟌ã¿å¯èœãªåäžã®ã¡ã¢ãªã»ã«ããªãå ŽåããŸããããäžè¬çãªã±ãŒã¹ã§ã¯ãè€æ°ã®ã¹ã¬ãããæžã蟌ãããšãã§ããåäžã®ãã£ãã·ã¥ã©ã€ã³ã¯ãããŸãããå ±æãã¥ãŒããã¯ã¹ãããªãŒããŒã®ã¿ã®ååšäžã§ãæžã蟌ã¿ç«¶åãªããšããŠåé¡ãããããã«ã¯ããªãŒããŒãäºãã«å¹²æžããªãããšãå¿ èŠã§ã-ã€ãŸããã®ãããåãªãŒããŒã¯èªåã®åå¥ã®ã»ã«ã«ãã©ã°ïŒèªã¿åã£ããã®ïŒãæžã蟌ã¿ãèªã¿åãã®æåŸã«åãã»ã«ã®ãã©ã°ãRMWæäœãªãã§åé€ããŸãã
æžã蟌ã¿ã³ã³ãã³ã·ã§ã³ããªãŒã¯æãçç£çãªä¿èšŒã§ãããåŸ æ©ããªãŒãããã¯ããªãŒãããçç£çã§ãã
åœå ±æãæé€ããããã«ãåã»ã«ãåå¥ã®ãã£ãã·ã¥ã©ã€ã³ã«é 眮ããå¿ èŠããããŸãããŸããã»ã«ãåããã£ãã·ã¥ã©ã€ã³ã®16ã«å³å¯ã«é 眮ãããå¯èœæ§ããããŸããããã©ãŒãã³ã¹ã®äœäžã¯CPUãšã¹ã¬ããã®æ°ã«äŸåããŸãã誀ã£ãå ±æãæé€ããã«ã¯ãåå€æ°ãåå¥ã®ãã£ãã·ã¥ã©ã€ã³ã«é 眮ããå¿ èŠããããŸãããã®ãããC ++ 17ã«ã¯ã¢ã©ã€ã¡ã³ãïŒstd :: hardware_destructive_interference_sizeïŒãååšãã以åã®ããŒãžã§ã³ã§ã¯ããã»ããµãŒäŸåã®ãœãªã¥ãŒã·ã§ã³char tmp [60]ã䜿çšã§ããŸããïŒx86_64ã§ã¯ããã£ãã·ã¥ã©ã€ã³ãµã€ãºã¯64ãã€ãã§ãïŒïŒ
//struct cont_free_flag_t { // alignas(std::hardware_destructive_interference_size) std::atomic<int> value; // C++17 // }; struct cont_free_flag_t { char tmp[60]; std::atomic<int> value; // tmp[] to avoid false sharing };
ãã©ã°ãèšå®ããåã«ããªãŒããŒã¯ã©ã€ã¿ãŒããããã©ããã確èªããŸããã€ãŸããæä»ããã¯ããããŸãããããŠä»¥æ¥å ±æãã¥ãŒããã¯ã¹ã¯ãã©ã€ã¿ãŒãéåžžã«å°ãªãå Žåã«äœ¿çšãããŸãã䜿çšããããã¹ãŠã®ã«ãŒãã«ã¯ãå ±æç¶æ ïŒSïŒã®ãã£ãã·ã¥L1ã«ãã®å€ã®ã³ããŒãä¿æã§ãããããã3ã¯ããã¯ãµã€ã¯ã«ã®éãã©ã€ã¿ãŒã®ãã©ã°ã®å€ãå€æŽããããŸã§ååŸãããŸã
ãã¹ãŠã®ã©ã€ã¿ãŒã«ã¯ããã€ãã®ããã«ã1ã€ã®åãwant_x_lockãã©ã°ããããŸã-ããã¯ãçŸæç¹ã§ã©ã€ã¿ãŒãããããšãæå³ããŸããã¹ã¬ããã©ã€ã¿ãŒã¯ãRââMWæäœã䜿çšããŠã€ã³ã¹ããŒã«ããã³åé€ããŸãã
lock(): while(!want_x_lock.compare_exchange_weak(flag, true, std::memory_order_acquire))
unlock(): want_x_lock.store(false, std::memory_order_release);
ãã ããèªè ãäºãã«å¹²æžããªãããã«ãç°ãªãã¡ã¢ãªã»ã«ã«å ±æããã¯ã«é¢ããæ å ±ãæžã蟌ãå¿ èŠããããŸãããããã®ããã¯çšã®é åãéžæããŸãããã³ãã¬ãŒããã©ã¡ãŒã¿ã§èšå®ããããµã€ãºã¯ãããã©ã«ãã§ã¯20ã§ããlock_sharedïŒïŒãåããŠåŒã³åºããããšãã¹ããªãŒã ã¯èªåçã«ç»é²ããããã®é åã®ç¹å®ã®å Žæãå æããŸããé åã®ãµã€ãºãããå€ãã®ã¹ã¬ãããããå Žåãlock_sharedïŒïŒãåŒã³åºããšãã®æ®ãã®ã¹ã¬ããã¯ã©ã€ã¿ãŒã§æä»ããã¯ãåŒãèµ·ãããŸããã¹ããªãŒã ã¯ãã£ãã«äœæãããããªãã¬ãŒãã£ã³ã°ã·ã¹ãã ãã¹ããªãŒã ãäœæããã®ã«ãããæéã¯éåžžã«é·ãããããªããžã§ã¯ãã«æ°ããã¹ããªãŒã ãç»é²ããæéã¯ãããããã§ãã
æãããªãšã©ãŒããªãããšã確èªããŸãããã¹ãŠãæ£ããæ©èœããããšãäŸã§ç€ºããŠãããã¢ãããŒãã®æ£ç¢ºæ§ãæŠç¥çã«èšŒæããŸãã
以äžã¯ããªãŒããŒãäºãã«å¹²æžããªãé«éå ±æããã¯ã®äŸã§ãã[30] coliru.stacked-crooked.com/a/b78467b7a3885e5b
- å ±æããã¯äžã¯ããªããžã§ã¯ããå€æŽããããšã¯ã§ããŸããã2ã€ã®ååž°çãªå ±æããã¯ã®ãã®è¡ã¯ãããã瀺ããŠããŸããassertïŒreadonly_safe_map_string-> atïŒ "apple"ïŒ== readonly_safe_map_string-> atïŒ "potato"ïŒïŒ; -äž¡æ¹ã®è¡ã®å€ã¯åžžã«çããã¯ãã§ãããªããªã stdã®2è¡ãå€æŽããŸã:: 1ã€ã®æä»ããã¯stdã®äžã®ããã:: lock_guard
- èªã¿åãäžã«ãå®éã«lock_sharedïŒïŒé¢æ°ãåŒã³åºããŸããã«ãŒãã2åã®å埩ã«æžãããããŒã¿ãå€æŽããè¡ãåé€ããstd :: mapã®æåã®2ã€ã®æ¿å ¥ã®ã¿ãmainïŒïŒé¢æ°ã«æ®ããŸãã次ã«ãSãšããæåã®åºåãlock_sharedïŒïŒé¢æ°ã«è¿œå ããXãšããæåãlockïŒïŒé¢æ°ã«è¿œå ããŸããæåã«2ã€ã®æ¿å ¥Xãããã次ã«æåSã ããããããšãããããŸããå®éã«ã¯ãconstãªããžã§ã¯ããèªã¿åããšãã«shared_lockïŒïŒãåŒã³åºããŸãïŒ[31] coliru.stacked-crooked.com/a/515ba092a46135ae
- å€æŽäžã«ãå®éã«lockïŒïŒé¢æ°ãåŒã³åºããŸããèªã¿åããã³ã¡ã³ãã¢ãŠãããé åãå€æŽããæäœã®ã¿ãæ®ããæåXã®ã¿ã衚瀺ãããããã«ãªããŸããã[32] coliru.stacked-crooked.com/a/882eb908b22c98d6
äž»ãªã¿ã¹ã¯ã¯ãåæã«2ã€ã®ç¶æ ã®ãã¡ã®1ã€ã®ã¿ãååšããããã«ããããšã§ãã
- ä»»æã®æ°ã®ã¹ã¬ãããlock_sharedïŒïŒãæ£åžžã«å®è¡ããŸããããlockïŒïŒãå®è¡ããããšãããã¹ãŠã®ã¹ã¬ããã¯åŸ æ©ããå¿ èŠããããŸã
- ã¹ã¬ããã®1ã€ãæ£åžžã«ããã¯ïŒïŒãå®è¡ããlock_sharedïŒïŒãŸãã¯lockïŒïŒãå®è¡ããããšããä»ã®ãã¹ãŠã®ã¹ã¬ããã¯åŸ æ©ããå¿ èŠããããŸã
æŠç¥çã«ãäºææ§ã®ããç¶æ ã®ããŒãã«ã¯æ¬¡ã®ããã«ãªããŸãã
2ã€ã®ã¹ã¬ãããåæã«æäœãå®è¡ããããšããŠããå Žåã®contention_free_shared_mutexã®ã¢ã«ãŽãªãºã ãæ€èšããŠãã ããã
- T1-read & T2-read: - lock_shared() â , .. , - (want_x_lock == false). , , â - , CAS-: want_x_lock = true.
- T1-write & T2-write: - (want_x_lock) true, CAS-: want_x_lock.compare_exchange_weak(); , recursive_spinlock_t, .
- T1-read & T2-write: - T1 , (want_x_lock), (true), , (want_x_lock == false) .
ã©ã€ã¿ãŒã¹ã¬ããT2ã¯ãã©ã°ãèšå®ãïŒwant_x_lock = trueïŒããã¹ãŠã®ãªãŒããŒã¹ã¬ãããã»ã«ããããã¯ãã©ã°ãåé€ããã®ãåŸ ã¡ãŸãã
ãã®ã¹ããŒã ã®ã©ã€ã¿ãŒã¹ã¬ããã¯ããªãŒããŒãããåªå 床ãé«ããªã£ãŠããŸãããŸããããã¯ãã©ã°ãåæã«èšå®ãããšã次ã®æäœã§ãªãŒããŒã¹ã¬ããã¯ã©ã€ã¿ãŒã¹ã¬ããããããã©ããã確èªãïŒwant_x_lock == trueïŒãããã§ããã°ããªãŒããŒã¯ãã®ããã¯ããã£ã³ã»ã«ããŸããã©ã€ã¿ãŒã¹ã¬ããã¯ããªãŒããŒããã®ããã¯ããã以äžãªãããšã確èªãããããã¯æ©èœãæ£åžžã«å®äºããŸãããããã®ããã¯ã®ã°ããŒãã«ãªé åºã¯ãSequential ConsistencyïŒstd :: memory_order_seq_cstïŒã®ã»ãã³ãã£ã¯ã¹ã«ããå°éãããŸãã
æŠç¥çã«ã¯ã2ã€ã®ã¹ããªãŒã ïŒãªãŒããŒãšã©ã€ã¿ãŒïŒã®çžäºäœçšã¯æ¬¡ã®ãšããã§ãã
ãã«ãµã€ãºã§ïŒhabrastorage.org/getpro/habr/post_images/5b2/3a3/23b/5b23a323b6a1c9e13ade90bbd82ed98b.jpg
äž¡æ¹ã®æäœã®äž¡æ¹lock_sharedé¢æ°ïŒïŒãšããã¯ã§ïŒïŒã1,2䜿çšã®std :: memory_order_seq_cst -ããªãã¡ ãããã®æäœã§ã¯ããã¹ãŠã®ã¹ã¬ããã«å¯ŸããŠåäžã®åèšé åºãä¿èšŒãããŸãã
cont-free shared-mutexã§ã¹ããªãŒã ãèªåçã«ç»é²è§£é€ããŸã
ã¹ã¬ãããæåã«ããã¯ã«ã¢ã¯ã»ã¹ãããšãç»é²ãããŸãããããŠããã®ã¹ã¬ãããå®äºããããããã¯ãåé€ããããšãç»é²ããã£ã³ã»ã«ããå¿ èŠããããŸãã
ãããã20åã®ã¹ã¬ããããã¥ãŒããã¯ã¹ã§åäœããããã¯é åã20ã§ããå Žåããããã®ã¹ã¬ãããçµäºããæ°ãã20åã®ã¹ã¬ãããç»é²ããããšãããšã©ããªãããèŠãŠã¿ãŸãããïŒ[33] coliru.stacked-crooked.com/a/ f1ac55beedd31966ã芧ã®
ãšãããæåã®20åã®ã¹ã¬ããã¯æ£åžžã«ç»é²ãããŸãããã次ã®20åã®ã¹ã¬ããã¯ç»é²ã§ããïŒregister_thread = -1ïŒãåã®20åã®ã¹ã¬ããã¯æ¢ã«åé€ãããŠããã¯ã䜿çšããŠããŸããããæä»çãªã©ã€ã¿ãŒããã¯ã®äœ¿çšã匷å¶ãããŸããã
ãã®åé¡ã解決ããããã«ãã¹ããªãŒã ãåé€ããããšãã«ã¹ããªãŒã ã®èªåç»é²è§£é€ãè¿œå ããŸããã¹ã¬ããããããã®ããã¯ã®å€ãã§æ©èœããå Žåãã¹ã¬ããã®çµäºæã«ããã¹ãŠã®ãã®ãããªããã¯ã§ç»é²è§£é€ãçºçããã¯ãã§ãããŸããã¹ããªãŒã ã®åé€æã«çŸåšåé€ãããŠããããã¯ãããå Žåãååšããªãããã¯ã§ç»é²ããã£ã³ã»ã«ããããšããŠãšã©ãŒãçºçããããšã¯ãããŸããã
äŸïŒ[34] coliru.stacked-crooked.com/a/4172a6160ca33a0fã芧ã®
ãšãããæåã«20åã®ã¹ã¬ãããç»é²ãããããããåé€ããŠ20åã®æ°ããã¹ã¬ãããäœæããåŸãç»é²ããããšãã§ããŸãã-åãçªå·ã§register_thread = 0-19ïŒåºåãåç §ïŒ ïŒåºåïŒã®äŸïŒã
ã¹ã¬ãããããã¯ã§åäœããããã¯ãåé€ãããå Žåã§ããã¹ã¬ãããå®äºãããšãååšããªãããã¯ãªããžã§ã¯ããç»é²è§£é€ããããšããŠãšã©ãŒãçºçããªãããšãããã ãŸãã[35] coliru.stacked-crooked.com/a/d2e5a4ba1cd787da
We 20ã¹ã¬ãããäœæãããããã¯ã䜿çšããŠèªã¿åããã500ããªç§ã§ã¹ãªãŒãç¶æ ã«ãªãããã«ã¿ã€ããŒãèšå®ããŸãããã®æç¹ã§ãcontention_free_shared_mutexããã¯ãå«ãcontfree_safe_ptrãªããžã§ã¯ãã100ããªç§åŸã«åé€ããããã®åŸ20ã¹ã¬ãããèµ·åããŠçµäºããŸãããããããå®äºãããšããªã¢ãŒãããã¯ãªããžã§ã¯ãã®ç»é²è§£é€ã«ãããšã©ãŒã¯çºçããŸããã§ããã
å°ããªè¿œå ãšããŠãMSVS2013ããµããŒãããããšã§ãå€ãã³ã³ãã€ã©ã®ææè ããã®äŸã«æ £ããããšãã§ããŸããç°¡çŽ åãããã¹ããªãŒã ç»é²ãµããŒããè¿œå ããŸãããã¹ããªãŒã ãç»é²è§£é€ããæ©èœã¯ãããŸããã
äžèšã®èãããã¹ãŠèæ ®ã«å ¥ããäŸãšããŠãæçµçµæã瀺ããŸãã
äŸïŒ[36] coliru.stacked-crooked.com/a/0a1007765f13aa0d
ã¢ã«ãŽãªãºã ãšéžæãããéå£ã®é©åãªæ©èœ
äžèšã§ã¯ãæãããªãšã©ãŒããªãããšã瀺ããã¹ããå®æœããŸãããããããæäœæ§ã蚌æããããã«ãæäœã®é åºãšå€æ°ã®å¯èœãªç¶æ ã®å¯èœãªå€æŽã®ã¹ããŒã ãäœæããå¿ èŠããããŸãã
æä»çããã¯ïŒïŒ/ããã¯è§£é€ïŒïŒããã¯ã¯ãrecursive_spinlock_tã®å Žåãšåããããç°¡åãªã®ã§ã詳现ã«æ€èšããŸããã
lock_sharedïŒïŒã®ãªãŒããŒã¹ã¬ãããšlockïŒïŒã®ã©ã€ã¿ãŒã¹ã¬ããã®ç«¶åã«ã€ããŠã¯ãäžã§è©³ãã調ã¹ãŸããã
ããã§ã®äž»ãªã¿ã¹ã¯ã¯ããã¹ãŠã®å Žåã§lock_sharedïŒïŒãå°ãªããšãAcquire-semanticã䜿çšããunlock_sharedïŒïŒããã¹ãŠã®å Žåã§å°ãªããšãRelease-semanticã䜿çšããããšã瀺ãããšã§ããããããããã¯ååž°çãªããã¯/ããã¯è§£é€ãç¹°ãè¿ãããã®åææ¡ä»¶ã§ã¯ãããŸããã
次ã«ããããã®éå£ãã³ãŒãã§ã©ã®ããã«å®è£ ããããã瀺ããŸãã
lock_sharedïŒïŒã®å³åŒã®éå£-é åºã®å€æŽãçŠæ¢ãããŠããæ¹åã瀺ãèµ€ãããå°ã®ç¢å°ïŒunlock_sharedïŒïŒã®
å³åŒã®éå£ïŒãã«ãµã€ãºïŒhsto.org/files/065/9ce/bd7/0659cebd72424256b6254c57d35c7d07.jpgããŒã¯ã¢ãŠãä»ãã®ãã«ãµã€ãºé·ç§»ïŒhsto.org/files/fa7/4d2/2b7/fa74d22b7cda4bf4b1015ee263cad9ee.jpgã®ååšã¯ãŸãããã®åãæ©èœã®ãããã¯å³ïŒïŒlock_shared ãã«ãµã€ãºã®ç»åãïŒhsto.org/files/c3a/abd/4e7/c3aabd4e7cfa4e9db55b2843467d878f.jpgãå æ¥å圢ã®ãããã¯ã¯ãå³å¯ãªäžé£ã®æäœã瀺ããŸãã
- æäœãæåã«å®è¡ãããŸã-èµ€ã§
- ãã®åŸãæäœãå®è¡ãããŸã-玫è²ã§
ç·è²ã¯ãä»»æã®é åºã§å®è¡ã§ããå€æŽã瀺ããŸãããããã®å€æŽã¯ãå ±æãã¥ãŒããã¯ã¹ãããããã¯ããŸããããååž°ãã¹ãã£ã³ã°ã«ãŠã³ã¿ãŒãå¢ããã ãã§ã-ãããã®å€æŽã¯ããŒã«ã«ã§ã®ã¿äœ¿çšããå Žåã«éèŠã§ããã€ãŸã ãããã®ç·ã®æäœã¯ãããã¯ãžã®å®éã®ãšã³ããªã§ã¯ãããŸããã
ãªããªã 2ã€ã®æ¡ä»¶ãæºããããŠããŸã-ãã«ãã¹ã¬ããããã®ãã¹ãŠã®å¿ èŠãªå¯äœçšãèæ ®ããããšèããããŸãïŒ
- ããã¯ãå
¥åãã決å®ã®ç¬éã«ã¯ãåžžã«ãååŸã以äžã®ã»ãã³ãã£ã¯ã¹ããã
ãŸããâ¢want_x_lock.loadïŒstd :: memory_order_seq_cstïŒ
â¢want_x_lock.compare_exchange_weakïŒflagãtrueãstd :: memory_order_seq_cstïŒ - (1-), (2-) . .
ããã«ããããã®æäœã®çµæãšãã®ã·ãŒã±ã³ã¹ãã¢ã«ãŽãªãºã ã®ããžãã¯ãšåçŽã«æ¯èŒããããšã«ãããã¢ã«ãŽãªãºã ã®æ£ç¢ºæ§ã確èªã§ããŸãã
ããããã³ã°ãcontention_free_shared_mutexãã®ä»ã®ãã¹ãŠã®æ©èœã¯ããã«ãã¹ã¬ããå®è¡ã®ããžãã¯ã®èŠ³ç¹ããããæçœã§ãã
ãŸããç¹°ãè¿ãïŒååž°ïŒãããã¯äžã«ãã¢ãããã¯æäœã«std :: memory_order_acquireããªã¢ãŒïŒå³ã«ç€ºãããã«ïŒã¯å¿ èŠãããŸãããããã¯ãå®éã®ããã¯ãšã³ããªã§ã¯ãªããããstd :: memory_order_relaxedãèšå®ããã ãã§ååã§ãã ããã ããããã«ãã£ãŠé床ãå€§å¹ ã«åäžããããšã¯ãªããç解ãè€éã«ãªããŸãã
䜿ãæ¹
C ++ã§contention_free_shared_mutex <>ãé«åºŠã«æé©åãããshared_mutexãšããŠäœ¿çšããäŸã瀺ããŸãã
LinuxïŒGCC 6.3.0ïŒããã³WindowsïŒMSVS 2015/13ïŒçšã®ãã®ã³ãŒãã¯ã次ã®å ŽæããããŠã³ããŒãã§ããŸãïŒgithub.com/AlexeyAB/object_threadsafe/tree/master/contfree_shared_mutex
Linuxã§Clang ++ 3.8.0ã§ãã®äŸãã³ã³ãã€ã«ããã«ã¯ãå€æŽããå¿ èŠããããŸãã¡ã€ã¯ãã¡ã€ã«ã
#include < iostream > #include < thread > #include < vector > #include "safe_ptr.h" template < typename T > void func(T &s_m, int &a, int &b) { for (size_t i = 0; i < 100000; ++i) { // x-lock for modification { s_m.lock(); a++; b++; s_m.unlock(); } // s-lock for reading { s_m.lock_shared(); assert(a == b); // will never happen s_m.unlock_shared(); } } } int main() { int a = 0; int b = 0; sf::contention_free_shared_mutex< > s_m; // 19 threads std::vector< std::thread > vec_thread(20); for (auto &i : vec_thread) i = std::move(std::thread([&]() { func(s_m, a, b); })); for (auto &i : vec_thread) i.join(); std::cout << "a = " << a << ", b = " << b << std::endl; getchar(); return 0; }
ãã®ã³ãŒãã¯ãªã³ã©ã€ã³ã³ã³ãã€ã©ã«ãããŸãïŒcoliru.stacked-crooked.com/a/11c191b06aeb5fb6ã芧ã®
ãšãããmutex sf :: contention_free_shared_mutex <>ã¯ãæšæºstd :: shared_mutexãšãŸã£ããåãããã«äœ¿çšãããŸãã
ãã¹ãïŒstd :: shared_mutex VS contention_free_shared_mutex
1ã€ã®ãµãŒããŒããã»ããµIntel Xeon E5-2660 v3 2.6 GHzã®16ã¹ã¬ããã§ãã¹ãããäŸã次ã«ç€ºããŸãããŸããéãšçŽ«ã®ç·ã«èå³ããããŸãã
- safe_ptr <std :: mapãstd :: shared_mutex>
- contfree_safe_ptr <std :: map>
ïŒãã¹ãã®ãœãŒã¹ã³ãŒãgithub.com/AlexeyAB/object_threadsafe/tree/master/bench_contfree
èµ·åããããã®ã³ãã³ãã©ã€ã³ïŒ
numactl --localalloc --cpunodebind = 0 ./benchmark 16
ã ããã¶ãŒããŒãäžã®CPUãæã£ãŠããå Žåã¯ãå®è¡ããŸãã /ãã³ãããŒã¯
èªã¿åãããã¯ïŒå ±æããã¯ïŒãšæžã蟌ã¿ããã¯ïŒæä»ããã¯ïŒã®ç°ãªãæ¯çã«å¯ŸããããŸããŸãªããã¯ã®ããã©ãŒãã³ã¹ã
- æä»ããã¯ã®å²å=ïŒæžã蟌ã¿æäœã®å²åïŒ
- å ±æããã¯ïŒ = 100-ïŒæžã蟌ã¿æäœã®ïŒ ïŒ
ïŒstd :: mutexã®å Žå-æä»ããã¯ã¯åžžã«æ©èœããŸãïŒ
ããã©ãŒãã³ã¹ïŒå€§ããã»ã©è¯ãïŒãMOps-æ¯ç§æ°çŸäžåã®æäœ
- å€æŽã0ïŒ ã®å Žåãå ±æmutexïŒcontfree_safe_ptr <map>ã®äžéšãšããŠïŒã¯34.60 Mopsã®ããã©ãŒãã³ã¹ã瀺ããæšæºstd :: shared_mutexïŒsafe_ptr <mapãstd :: shared_mutex>ã®äžéšãšããŠïŒããã14åé«éã§ãã 2.44ã¢ããã®ã¿ã
- 15ïŒ ã®å€æŽã«ãããå ±æãã¥ãŒããã¯ã¹ïŒcontfree_safe_ptr <map>ã®äžéšãšããŠïŒã¯5.16 Mopsããã©ãŒãã³ã¹ã瀺ããæšæºstd :: shared_mutexïŒsafe_ptr <mapãstd :: shared_mutex>ã®äžéšïŒããã7åé«éã§ãã 0.74ã¢ããã®ã¿ã
ã競åã®ãªãå ±æãã¥ãŒããã¯ã¹ãããã¯ã¯ãä»»æã®æ°ã®ã¹ã¬ããã§æ©èœããŸããæåã®36åã®ã¹ã¬ããã§ã¯ç«¶åãªããåŸç¶ã®ã¹ã¬ããã§ã¯æä»ããã¯ãšããŠæ©èœããŸããã°ã©ããããããããã«ããæä»ããã¯ãã®std :: mutexã§ãããstd :: shared_mutexãããé«éã§ã15ïŒ ã®å€æŽããããŸãã
ã³ã³ãã³ã·ã§ã³ããªãŒã®ã¹ããªãŒã 36ã®æ°ã¯ããã³ãã¬ãŒããã©ã¡ãŒã¿ã«ãã£ãŠèšå®ãããå€æŽã§ããŸãã
次ã«ãããã¯ã®ã¿ã€ãã®ç°ãªãæ¯çïŒèªã¿åãïŒå ±æããã¯ïŒãšæžã蟌ã¿ïŒæä»ããã¯ïŒïŒã®é 延ã®äžå€®å€ã瀺ããŸãã
main.cppãã¹ãã³ãŒãã§ã¯ã次ãèšå®ããå¿ èŠããããŸããconst bool measure_latency = true;
å®è¡ããã³ãã³ãã©ã€ã³ïŒ
numactl --localalloc --cpunodebind = 0 ./benchmark 16
ãã¶ãŒããŒãã«CPUã1ã€ãããªãå Žåã¯ã次ãå®è¡ããŸãïŒ./benchmark
ã¬ã€ãã³ã·ã®äžå€®å€ïŒäœã-è¯ãïŒããã€ã¯ãç§
ãããã£ãŠãstd :: shared_timed_mutexããã³boost :: shared_mutexãšã¯ç°ãªããããã¯ããã³ããã¯è§£é€äžã«ãªãŒããŒãäºãã«å¹²æžããªãå ±æããã¯ãäœæããŸããããã ããåã¹ã¬ããã«è¿œå ã§å²ãåœãŠãããŠããŸããããã¯é åã®64ãã€ã+ 24ãã€ãã¯ãç»é²è§£é€ã®ããã®unregister_tæ§é äœ+ hash_mapãããã®æ§é äœãæãèŠçŽ ã§å ããããŠããŸããåèšã§ãã¹ããªãŒã ããšã«çŽ100ãã€ãã
ããæ·±ãåé¡ã¯ãã¹ã±ãŒãªã³ã°ããèœåã§ããããšãã°ã24åã®ã³ã¢ïŒãããã48åã®ãã€ããŒã¹ã¬ããã£ã³ã°ã¹ã¬ããïŒãåãã8åã®CPUïŒIntel Xeon Processor E7-8890 v4ïŒãããå Žåãããã¯åèš384åã®è«çã³ã¢ã«ãªããŸããåã©ã€ã¿ãŒã¹ã¬ããã¯ãæžã蟌ã¿åã«24,576ãã€ãïŒå384ã³ã¢ãã64ãã€ãïŒãèªã¿åãå¿ èŠããããŸããã䞊è¡ããŠèªã¿åãããšãã§ããŸããããã¯ã1ã€ã®ãã£ãã·ã¥ã©ã€ã³ãå384ã¹ã¬ããããåã¹ã¬ããã«é 次移åãããŸã§åŸ ã€ããã確ãã«åªããŠããŸããéåžžã®std :: shared_timed_mutexããã³boost :: shared_mutexïŒä»»æã®ã¿ã€ãã®ãŠããŒã¯/å ±æããã¯ïŒããã ãã1000ã³ã¢ä»¥äžã®äžŠååã¯éåžžãåã¡ãã»ãŒãžãåŠçããã¢ãããã¯æäœãåŒã³åºãã®ã§ã¯ãªããç°ãªãã¢ãããŒãã§å®è£ ãããŸããäžèšã§èª¬æãããã¹ãŠã®ãªãã·ã§ã³ïŒã¢ãããã¯æäœãã¢ã¯ãã£ãããã¯ãããã¯ã®ãªãããŒã¿æ§é -ãããã¯ãã¹ãŠãäœã¬ã€ãã³ã·ïŒ0ã5-5 usecïŒåã ã®ã¡ãã»ãŒãžã
1ç§ãããã®æäœçãé«ãå Žåãã€ãŸãã·ã¹ãã å šäœã®ããã©ãŒãã³ã¹ãšæ°äžã®è«çã³ã¢ã®ã¹ã±ãŒã©ããªãã£ã®ããã«ã倧é䞊ååŠçããã¬ã€ãã³ã·ãé ãããããããåŠçãã®ã¢ãããŒãã䜿çšããŸããã¡ãã»ãŒãžããœãŒãïŒãããçšïŒãŸãã¯ã°ã«ãŒãåïŒããã·ã¥ãããçšïŒãããæ¢åã®ãœãŒãæžã¿ã®ãã®ãšããŒãžãããå Žåã®ãããåŠçãŸãã¯50ã500 usecã®ã°ã«ãŒãåãããé åããã®çµæãåæäœã«ã¯10ã100åã®é 延ããããŸããããããã®é 延ã¯èšå€§ãªæ°ã®ã¹ã¬ããã§åæã«çºçãããã®çµæããFine-grained Temporal multithreadingãã®äœ¿çšã«ããã¬ã€ãã³ã·ãé衚瀺ã¬ã€ãã³ã·ããé ãããŸãã
ä»®å®ãããšãåã¡ãã»ãŒãžã«ã¯100åã®é 延ããããŸãããã¡ãã»ãŒãžã¯10,000ååŠçãããŸããããã¯ãåäœæéããã100åå¹æçã§ãã GPUã§éçºããå Žåããã®ãããªååãé©çšãããŸãããããã以äžã®èšäºã§ããããã詳现ã«åæããŸãã