䜿çšäŸãšã¹ã¬ããã»ãŒããã€ã³ã¿ãŒãšç«¶åã®ãªãå ±æãã¥ãŒããã¯ã¹ã®ãã¹ã
ãã®èšäºã§ã¯ãè¿œå ã®æé©åã䜿çšäŸãããã³æé©åãããå ±æãã¥ãŒããã¯ã¹contfree_safe_ptr <T>ã§éçºããã¹ã¬ããã»ãŒããã€ã³ã¿ãŒã®ãã¹ãã®äŸã瀺ããŸããããã¯safe_ptr <Tãcontention_free_shared_mutex <>>ãšåçã§ãã
æåŸã«ãã¹ã¬ããã»ãŒããã€ã³ã¿ãŒã®ãã¹ããšãIntel Core i5 / i7ãXeonã2 x Xeonããã»ããµäžã®libCDSã®æé«ã®ããã¯ããªãŒã¢ã«ãŽãªãºã ã®ãã¹ãã®æ¯èŒã°ã©ãã瀺ããŸãã
é¢é£ãã3ã€ã®èšäºïŒ
- ãªããžã§ã¯ããã¹ã¬ããã»ãŒãã«ãã
- stdã®é«éå:: shared_mutexã10å
- ã¹ã¬ããã»ãŒãstd ::ããã¯ã®ãªããããããã©ãŒãã³ã¹ãåããããã
â ç§ã®è±èªã®èšäº
â 3ã€ã®èšäºãã¹ãŠã®äŸãšãã¹ã
ãªã³ã¯ã§ãœãªã¥ãŒã·ã§ã³ãæ¯èŒããlibCDSã©ã€ãã©ãªãèŠã€ããããšãã§ããŸãïŒ github.com/khizmax/libcds
ãã®èšäºã®ãã¹ãŠã®ãã¹ãã¯ãlibCDSããã®æ¬¡ã®ã³ãããã䜿çšããŸããgithub.com/ khizmax / libcds / tree / 5e2a9854b0a8625183818eb8ad91e5511fed5898
ç°ãªãç²åºŠã®ããã¯
æåã«ãããŒãã«ïŒæ§é äœã®é åïŒãæäœããäŸã䜿çšããŠãå ±æãã¥ãŒããã¯ã¹ãæé©ã«äœ¿çšããæ¹æ³ã瀺ããŸãã ç£æ¥çšDBMSã®çµéšãèŠãŠã¿ãŸãããã ããšãã°ãMSSQL DBMSã§ã¯ãããŸããŸãªç²åºŠã®ããã¯ã䜿çšãããŸããããã¯ïŒ1ã€ä»¥äžã®è¡ãããŒãžããšã¯ã¹ãã³ããããŒãã«ã®1ã€ã®ã»ã¯ã·ã§ã³ãã€ã³ããã¯ã¹ãããŒãã«å šäœãããŒã¿ããŒã¹å šäœã https://technet.microsoft.com/en-us/library/ms189849(v=sql.105).aspx
å®éãé·ãé1ã€ã®è¡ãæäœããŠããããã®æç¹ã§è¡ãå¥ã®ã¹ã¬ããã«ãã£ãŠå€æŽãããªãããšãéèŠãªå Žåããã®æç¹ã§ããŒãã«å šäœãããã¯ããå¿ èŠã¯ãããŸãã-1è¡ã®ã¿ãããã¯ããã ãã§ååã§ãã
- å ±æããã¯ã§ããŒãã«å šäœãããã¯ããŸã
- ç®çã®è¡ãŸãã¯è€æ°ã®è¡ãæ¢ããŠããŸã
- 次ã«ãèŠã€ãã£ãè¡ããããã¯ããŸã
- ããŒãã«ã®ããã¯ã解é€ããŸã
- ããã¯ãããè¡ã§ã®äœæ¥
ãã®åŸãä»ã®ã¹ã¬ãããæ®ãã®è¡ã䞊è¡ããŠåŠçã§ããããã«ãªããŸãã
ãããŸã§ãããŒãã«ã¬ãã«ã®ããã¯ã®ã¿ã䜿çšããŸããã 1ã€ä»¥äžã®ããŒãã«ããããã¯ããŸããã
ãŸãã¯ãåŒã§äœ¿çšããããã¹ãŠã®ããŒãã«ã¯ãå®äºãããŸã§èªåçã«ããã¯ãããŠããŸããã
(*safe_map_1)["apple"].first = "fruit"; // locked Table-1 (safe_map_1) // unlocked Table-1 safe_map_1->at("apple").second = safe_map_1->at("apple").second * 2; // locked Table-1 (safe_map_1) // unlocked Table-1 safe_map_1->at("apple").second = safe_map_2->at("apple").second*2; // locked Table-1(safe_map_1) and Table-2(safe_map_2) // unlocked Table-1 and Table-2
ãã®ä»ã®å ŽåãRAIIããã¯ãªããžã§ã¯ãã䜿çšããŠããããã®ããã¯ã®ãããã¯ã¹ã³ãŒããçµäºãããŸã§ïŒç Žæ£ããããŸã§ïŒã1ã€ä»¥äžã®ããŒãã«ãæåã§ãããã¯ããŸããã
{ std::lock_guard<decltype(safe_map_1)> lock(safe_map_1); // locked Table-1 (safe_map_1) (*safe_map_1)["apple"].first = "fruit"; safe_map_1->at("apple").second = safe_map_1->at("apple").second * 2; // unlocked Table-1 } { lock_timed_any_infinity lock_all(safe_map_1, safe_map_2); // locked Table-1(safe_map_1) and Table-2(safe_map_2) safe_map_1->at("apple").second = safe_map_2->at("apple").second*2; //locked Table-1(safe_map_1) and Table-2(safe_map_2) safe_map_1->at("potato").second = safe_map_2->at("potato").second*2; //locked Table-1(safe_map_1) and Table-2(safe_map_2) // unlocked Table-1 and Table-2 }
æ¿å ¥ããã€ã³ããã¯ã¹ãã©ã³ãã ã«éžæãã次ã«4ã€ã®æäœïŒæ¿å ¥ãåé€ãæŽæ°ãèªã¿åãïŒã®ãããããã©ã³ãã ã«éžæããŠã contfree_safe_ptr <std :: map>åã®ã¹ã¬ããã»ãŒããªããžã§ã¯ãã§å®è¡ããäŸãèŠãŠã¿ãŸãããã
äŸïŒ[37] coliru.stacked-crooked.com/a/5b68b65bf2c5abeb
ãã®å ŽåãããŒãã«ã«æ¬¡ã®ããã¯ã課ããŸãã
- æ¿å ¥-æä»çããã¯
- åé€-æä»çããã¯
- æŽæ°-æä»çããã¯
- èªã¿åã-å ±æããã¯
æŽæ°ãŸãã¯èªã¿åãæäœã®å Žåã次ã®ããšãè¡ããŸãã
- ããŒãã«å šäœãããã¯ããŸãïŒæŽæ°ã®å Žåã¯xlockãèªã¿åãã®å Žåã¯slockïŒ
- å¿ èŠãªè¡ãæ€çŽ¢ããèªã¿åããŸãã¯å€æŽããŸã
- ããŒãã«ã®ããã¯ã解é€ããŸã
ãã®äŸã®1ã€ã®å埩ã®ã³ãŒãã¯1ã§ãã
int const rnd_index = index_distribution(generator); // 0 - container_size int const num_op = operation_distribution(generator);// insert_op, update_op, delete_op, read_op switch (num_op) { case insert_op: { safe_map->emplace(rnd_index, (field_t(rnd_index, rnd_index))); // insert with X-lock on Table break; } case delete_op: { size_t erased_elements = safe_map->erase(rnd_index); // erase with X-lock on Table } break; case update_op: { auto x_safe_map = xlock_safe_ptr(safe_map); // X-lock on Table auto it = x_safe_map->find(rnd_index); if (it != x_safe_map->cend()) { it->second.money += rnd_index; // still X-lock on Table (must necessarily be) } } break; case read_op: { auto s_safe_map = slock_safe_ptr(safe_map); // S-lock on Table auto it = s_safe_map->find(rnd_index); if (it != s_safe_map->cend()) { volatile int money = it->second.money; // still S-lock on Table (must necessarily be) // volatile here only to avoid optimization for unused money-variable } } break; default: std::cout << "\n wrong way! \n"; break; }
ããã§ãæŽæ°æäœäžã«ããŒãã«ãããã¯ããã¯ïŒæä»çïŒã§ã¯ãªããèªã¿åãããã¯ïŒå ±æïŒã«ãã£ãŠããã¯ãããããã«ããŸãã ããã«ããã以åã«éçºãããæžã蟌ã¿ç«¶åã®ãªãå ±æãã¥ãŒããã¯ã¹ãã䜿çšããéã®æŽæ°æäœãå€§å¹ ã«å éãããŸãã
ãã®å Žåãå€ãã®ã¹ã¬ãããåãããŒãã«ã§æŽæ°æäœãšèªã¿åãæäœãåæã«å®è¡ã§ããŸãã ããšãã°ã1ã€ã®ã¹ã¬ããã1è¡ãèªã¿åããå¥ã®ã¹ããªãŒã ãå¥ã®è¡ãå€æŽããŸãã ããããããã¹ã¬ãããå¥ã®ã¹ããªãŒã ãèªã¿åãã®ãšåãè¡ãå€æŽããããšããå ŽåãããŒã¿ç«¶åãåé¿ããããã«ãèªã¿åãæããã³å€æŽæã«è¡èªäœããããã¯ããå¿ èŠããããŸãã
äŸïŒ[38] coliru.stacked-crooked.com/a/89f5ebd2d96296d3
æŽæ°ãŸãã¯èªã¿åãæäœã®å ŽåïŒ
- å ±æããã¯ã§ããŒãã«å šäœãããã¯ããŸã
- ç®çã®è¡ãŸãã¯è€æ°ã®è¡ãæ¢ããŠããŸã
- 次ã«ãèŠã€ãã£ãè¡ããããã¯ããŸãïŒæŽæ°ã®å Žåã¯xlockãèªã¿åãã®å Žåã¯slockïŒ
- ãããŠãããã¯ãããè¡ïŒX / Sããã¯ïŒãšããã¯ãããããŒãã«ïŒSããã¯ïŒã§äœæ¥ããŸã
- ã©ã€ã³ã®ããã¯ã解é€
- ããŒãã«ã®ããã¯ã解é€ããŸã
Diff-å€æŽç¹ïŒ

ãã®äŸã®1ã€ã®å埩ã®ã³ãŒãã¯2ã§ãã
int const rnd_index = index_distribution(generator); // 0 - container_size int const num_op = operation_distribution(generator);// insert_op, update_op, delete_op, read_op switch (num_op) { case insert_op: { safe_map->emplace(rnd_index, (field_t(rnd_index, rnd_index))); // insert with X-lock on Table break; } case delete_op: { size_t erased_elements = safe_map->erase(rnd_index); // erase with X-lock on Table } break; case update_op: { auto s_safe_map = slock_safe_ptr(safe_map); // S-lock on Table auto it = s_safe_map->find(rnd_index); if (it != s_safe_map->cend()) { auto x_field = xlock_safe_ptr(it->second); x_field->money += rnd_index; // X-lock on field, still S-lock on Table (must necessarily be) } } break; case read_op: { auto s_safe_map = slock_safe_ptr(safe_map); // S-lock on Table auto it = s_safe_map->find(rnd_index); if (it != s_safe_map->cend()) { auto s_field = slock_safe_ptr(it->second); volatile int money = s_field->money; // S-lock on field, still S-lock on Table (must necessarily be) // volatile here only to avoid optimization for unused money-variable } } break; default: std::cout << "\n wrong way! \n"; break; }
ããã§ã¯ãã¹ã¬ããã»ãŒããªæåååŠçã®ããã«ãsafe_objã䜿çšããŸããã Safe_obj <T>ã«ã¯ãsafe_ptr <T>ã®ããã«ãã¿ã€ãTã®ãªããžã§ã¯ããå«ãŸããŠããŸããããããžã®ãã€ã³ã¿ã¯å«ãŸããŠããŸããã ãããã£ãŠãsafe_objã䜿çšããå Žåãsafe_ptrã§å¿ èŠãªããã«ããªããžã§ã¯ãèªäœã«ã¡ã¢ãªãåå¥ã«å²ãåœãŠãŠã¢ãããã¯åç §ã«ãŠã³ã¿ãŒãå€æŽããå¿ èŠã¯ãããŸããã ãããã£ãŠãsafe_ptrã䜿çšãããããsafe_objã䜿çšãããšãæ¿å ¥ãšåé€ã®æäœãã¯ããã«éããªããŸãã
safe_objãã³ããŒãããšããã³ããŒãããã®ã¯ãªããžã§ã¯ããã€ã³ã¿ã§ã¯ãªãããªããžã§ã¯ãèªäœãã³ããŒããã以åã«ãœãŒã¹ãšæçµçãªsafe_objãããã¯ãããŠããããšã«æ³šæãã䟡å€ããããŸãã
泚ïŒå³å¯ã«èšãã°ãè¡å šäœããããã¯ããã®ã§ã¯ãªããæ¢ããŠããè¡ã€ã³ããã¯ã¹ãé€ãè¡ã®ãã¹ãŠã®ãã£ãŒã«ãããããã¯ããŸãã ãããã£ãŠãè¡ã§ã¯ãªããªããžã§ã¯ããã£ãŒã«ãã«ååãä»ããŸããã ãŸãããã®æ¹æ³ã§åŒ·èª¿ããããã«ã1ã€ã®è¡ã ãã§ãªããå¥ã ã®safe_obj-objectsã«é 眮ãããšã1ã€ã®è¡ã®ãã£ãŒã«ãããããã¯ã§ããŸãã ããã«ãããç°ãªãã¹ã¬ãããç°ãªããã£ãŒã«ãããããã¯ãããããã䞊è¡ããŠåŠçã§ããããã«ãªããŸãã
ããã§ãããŸããŸãªæäœã«æ¬¡ã®ããã¯ã䜿çšããŸãã

ãã®äŸã¯ãå€æ°ã®çæéã®æäœã«å¯ŸããŠéåžžã«é«éã§ãã ãã ããè¡ïŒãã£ãŒã«ãïŒã®å€æŽãŸãã¯èªã¿åãã®ããã»ã¹ã§ã¯ãããŒãã«ã®èªã¿åãããã¯ïŒå ±æïŒãä¿æããŠããŸãã ãŸããããŒãã«ã®è¡ã«å¯ŸããŠãŸãã§ã¯ãããéåžžã«é·ãæäœãããå Žåã¯ãããããã¹ãŠãé·æéããŒãã«å šäœã§ããã¯ãããŸãã
ãã ããã¿ã¹ã¯ã®ããžãã¯ã«åŸã£ãŠãããã¹ã¬ãããè¡ãåé€ã§ãããã©ãããå¥ã®ã¹ã¬ãããåãè¡ãèªã¿åããŸãã¯å€æŽããŠããå Žåã¯ãè¡æ€çŽ¢ã®æéã ãããŒãã«ãããã¯ããã ãã§ååã§ãã ãŸããå¥ã®ã¹ã¬ãããè¡ãåé€ãããšãã«è§£æŸãããã¡ã¢ãªã«ã¢ã¯ã»ã¹ããªãããã«ããã«ã¯ãstd :: shared_ptr <T>-ã¢ãããã¯ã¹ã¬ããã»ãŒãåç §ã«ãŠã³ã¿ãŒãæã€ãã€ã³ã¿ãŒã䜿çšããå¿ èŠããããŸãã ãã®å Žåããã®è¡ãžã®ãã€ã³ã¿ãæã€ã¹ã¬ããããªãå Žåã«ã®ã¿ãã¡ã¢ãªã解æŸãããŸãã
safe_objã®ä»£ããã«ãsafe_ptrã䜿çšããŠæååãä¿è·ããŸãã ããã«ããããã€ã³ã¿ãæååã«ã³ããŒããsafe_ptrã«å«ãŸããstd :: shared_ptr <T>ã®ã¹ã¬ããã»ãŒãåç §ã«ãŠã³ã¿ã䜿çšã§ããŸãã
äŸïŒ[39] coliru.stacked-crooked.com/a/f2a051abfbfd2716
æŽæ°ãŸãã¯èªã¿åãæäœã®å ŽåïŒ
- å ±æããã¯ã§ããŒãã«å šäœãããã¯ããŸã
- ç®çã®è¡ãŸãã¯è€æ°ã®è¡ãæ¢ããŠããŸã
- 次ã«ãèŠã€ãã£ãè¡ããããã¯ããŸãïŒæŽæ°ã®å Žåã¯xlockãèªã¿åãã®å Žåã¯slockïŒ
- ããŒãã«ã®ããã¯ã解é€ããŸã
- ãããŠãå¿ èŠãªéãããã¯ãããã©ã€ã³ïŒX / Sããã¯ïŒã䜿çšããŸã
- ã©ã€ã³ã®ããã¯ã解é€
Diff-å€æŽç¹ïŒ

äŸ3ïŒ
int const rnd_index = index_distribution(generator); // 0 - container_size int const num_op = operation_distribution(generator);// insert_op, update_op, delete_op, read_op safe_ptr_field_t safe_nullptr; switch (num_op) { case insert_op: { safe_map->emplace(rnd_index, (field_t(rnd_index, rnd_index))); // insert with X-lock on Table break; } case delete_op: { size_t erased_elements = safe_map->erase(rnd_index); // erase with X-lock on Table } break; case update_op: { auto pair_result = [&]() { auto s_safe_map = slock_safe_ptr(safe_map); // S-lock on Table auto it = s_safe_map->find(rnd_index); if (it != s_safe_map->cend()) return std::make_pair(it->second, true); // found else return std::make_pair(safe_nullptr, false); // null-value }(); // unlock Table if(pair_result.second) { auto x_field = xlock_safe_ptr(pair_result.first); // X-lock on field x_field->money += rnd_index; // if a long time is read } // unlock field } break; case read_op: { auto pair_result = [&]() { auto s_safe_map = slock_safe_ptr(safe_map); // S-lock on Table auto it = s_safe_map->find(rnd_index); if (it != s_safe_map->cend()) return std::make_pair(it->second, true); // found else return std::make_pair(safe_nullptr, false); // null-value }(); // unlock Table if(pair_result.second) { auto s_field = slock_safe_ptr(pair_result.first); // S-lock on field volatile int money = s_field->money; // if a long time is read // volatile here only to avoid optimization for unused money-variable } // unlock field } break; default: std::cout << "\n wrong way! \n"; break; }
é©åã«èšèšããããã«ãã¹ã¬ããããã°ã©ã ã¯ãå ±æãªããžã§ã¯ããžã®çãåŒã³åºãã䜿çšãããããå°æ¥ãçãèªã¿åãæäœã®æåŸã§ã¯ãªãæåŸãã2çªç®ã®äŸã䜿çšããŸãã
ã€ãã£ãªã åšèŸºã®å®è¡ã®çæ
èããããåé¡ãèŠãŠãã³ãŒããæ¹å€ããŸãããã åã®ç« ã§ã¯ãé¢æ°ã䜿çšããŠæŽæ°æäœãšèªã¿åãæäœã®ãããã¯ã¿ã€ããæ瀺çã«èšå®ãããããªã䟿å©ã§é«æ§èœãªäŸãæ€èšããŸããã
- slock_safe_ptrïŒïŒ -èªã¿åãå°çš
- xlock_safe_ptrïŒïŒ -èªã¿åãããã³å€æŽçš
ããã§ã¯ããããã®é¢æ°ã«ãã£ãŠè¿ãããlock_objãªããžã§ã¯ãã®å¯¿åœãçµäºãããŸã§ããã¯ãä¿æãããŸããauto lock_obj = slock_safe_ptrïŒsf_pïŒ;
ãã ããæ¿å ¥ããã³åé€æäœã§ã¯ãæé»çãªããã¯ã䜿çšãããŸããã safe_ptr <std :: map>ãªããžã§ã¯ãã¯ãExecute Around Pointerã€ãã£ãªã ã䜿çšããŠèªåçã«ãããã¯ãããæ¿å ¥ãŸãã¯åé€æäœã®å®äºåŸããã«ããã¯è§£é€ãããŸããã
äŸïŒ[40] coliru.stacked-crooked.com/a/89f5ebd2d96296d3
ãã ããæŽæ°æäœãšèªã¿åãæäœã§æ瀺çãªããã¯ã䜿çšããããšãå¿ããããšããããŸãã ãã®å Žåãæ€çŽ¢æäœãå®äºããçŽåŸã«safe_ptr <std :: map>ã®ããã¯ã解é€ãããåŒãç¶ã䜿çšããŸãïŒ
- å¥ã®ã¹ã¬ããã«ãã£ãŠç¡å¹ã«ã§ããã€ãã¬ãŒã¿ãèŠã€ãããŸãã
- ãŸãã¯ãå¥ã®ã¹ã¬ããã§åé€ã§ããèŠã€ãã£ãã¢ã€ãã
ãã®åé¡ãéšåçã«è§£æ±ºããã«ã¯ãsafe_ptr <>ããã³safe_obj <>ã®ä»£ããã«safe_hide_ptr <>ããã³safe_hide_obj <>ã䜿çšã§ããŸãããããã¯ãã€ã³ã¿ã®åšå²ã§å®è¡ã䜿çšãããæ瀺çãªãããã¯åŸã«ã®ã¿ã¯ã©ã¹ã¡ã³ããŒã«ã¢ã¯ã»ã¹ã§ããŸãïŒ
safe_hide_obj<field_t, spinlock_t> field_hide_tmp; //safe_obj<field_t, spinlock_t> &field_tmp = field_hide_tmp; // conversion denied - compile-time error //field_hide_tmp->money = 10; // access denied - compile-time error auto x_field = xlock_safe_ptr(field_hide_tmp); // locked until x_field is alive x_field->money = 10; // access granted
äŸïŒ[41] coliru.stacked-crooked.com/a/d65deacecfe2636b
以åã®å Žåãééããç¯ããŠæ¬¡ã®ããã«æžãããšãã§ããŸã- ééã£ãã³ãŒãïŒ
auto it = safe_map->find(rnd_index); // X-lock, find(), X-unlock if (it != s_safe_map->cend()) volatile int money = it->second ->money; // X-lock, operator=(), X-unlock
ããã§ããã®åŒã³åºãã¯ã³ã³ãã€ã«ãããããªããžã§ã¯ãã®æ瀺çãªãããã¯ãå¿ èŠã«ãªããŸã- æ£ããã³ãŒãïŒ
auto s_safe_map = slock_safe_ptr(safe_map); // S-lock on Table auto it = s_safe_map->find(rnd_index); if (it != s_safe_map->cend()) { auto s_field = slock_safe_ptr(it->second); volatile int money = s_field->money; // S-lock on field, still S-lock on Table // volatile here only to avoid optimization for unused money-variable } // S-unlock Table, S-unlock field
ãã ããããã¯ãäžæãªããžã§ã¯ããšããŠäœ¿çšããå±éºæ§ã¯ãŸã ãããŸã ãããã¯æ£ãããããŸãã ã
auto it = slock_safe_ptr(safe_map)->find(rnd_index); // S-lock, find(), S-unlock if (it != s_safe_map->cend()) { volatile int money = slock_safe_ptr(it->second)->money; // S-lock, =, S-unlock }
次ã®éžæè¢ããããŸãã
- safe_ptrãšsafe_objã䜿çšããŠããªããžã§ã¯ããæ瀺çãŸãã¯èªåçã«ïŒã€ãã£ãªã ã®åšå²ã§å®è¡ïŒãããã¯ã§ããããã«ããŸãã
- ãŸãã¯ã safe_hide_ptrãšsafe_hide_objã䜿çšããŠããªããžã§ã¯ããæ瀺çã«ããã¯ããæ©èœã®ã¿ãæ®ããŸã
äœãéžæãããã¯ããªã次第ã§ãïŒ
- 䟿å©ãªèªåãããã¯ã䜿çšããïŒã€ãã£ãªã åšèŸºã§å®è¡ïŒ
- ãŸãã¯ããªããžã§ã¯ããæ瀺çã«ããã¯ããããã«èŠæ±ããããšã«ããããšã©ãŒã®å¯èœæ§ããããã«æžãããŸã
ããã«ã次ã®é¢æ°ãstd :: map <>ã®C ++ 17æšæºã«è¿œå ãããäºå®ã§ãã
- insert_or_assignïŒïŒ -èŠçŽ ãããã°å²ãåœãŠãããã§ãªããã°æ¿å ¥
- try_emplaceïŒïŒ -èŠçŽ ããªãå ŽåãèŠçŽ ãäœæããŸã
- mergeïŒïŒ -2ã€ã®ãããã1ã«ããŒãžããŸã
- extractïŒïŒ -èŠçŽ ãååŸãããããããåé€ããŸã
ãã®ãããªé¢æ°ã®å°å ¥ã«ãããã€ãã¬ãŒã¿ãŒã䜿çšããã«é »ç¹ã«äœ¿çšãããè€åæäœãå®è¡ã§ããŸãããã®å Žåãã€ãã£ãªã ã®å®è¡ã䜿çšãããšããããã®æäœã®ã¹ã¬ããã»ãŒããåžžã«ä¿èšŒãããŸãã äžè¬ã«ããã¹ãŠã®ã³ã³ããïŒstd :: arrayããã³std :: vector arrayãé€ãïŒã®ã€ãã¬ãŒã¿ãé¿ããããšã¯ããã«ãã¹ã¬ããããã°ã©ã ãæ§ç¯ããäžã§å€§ããªå©ãã«ãªããŸãã å埩åã䜿çšããé »åºŠãå°ãªãã»ã©ããã®ã¹ã¬ãããŸãã¯å¥ã®ã¹ã¬ããã«ãã£ãŠç¡å¹ã«ãããŠããå埩åã«ã¢ã¯ã»ã¹ããå¯èœæ§ã¯äœããªããŸãã ãã ããã€ãã¬ãŒã¿ã®æŠå¿µã¯ãã«ãã¹ã¬ããã®æŠå¿µãšççŸããŸãããããšãã°ãDBMSïŒOracleãMSSQLïŒã¯ã«ãŒãœã« ïŒã€ãã¬ãŒã¿ã®ã¢ããã°ïŒããã³ãã©ã³ã¶ã¯ã·ã§ã³ã®ç°ãªãã¬ãã«ã®åé¢ïŒãã«ãã¹ã¬ããã®ç°ãªãæŽåæ§ïŒããµããŒãããŸãã
ããããããªããéžã¶ãã®ã¯äœã§ãïŒã€ãã£ãªã ã®åšãã§å®è¡ã䜿çšãã safe_hide_ptrã«æ瀺çãªããã¯ã䜿çšã ãããããæåŠããæšæºã®std :: mutexããã¯ã䜿çšããŸã...ãŸãã¯ç¬èªã®ããã¯ããªãŒã¢ã«ãŽãªãºã ãèšè¿°ããŸã-ããªãã¯åžžã«ééããç¯ãå€ãã®ãªãã·ã§ã³ããããŸãã

ããŒãã«ã®ããŒãã£ã·ã§ã³-ããã©ãŒãã³ã¹ãããã«åäžããã
ç£æ¥çšãªã¬ãŒã·ã§ãã«DBMSã®çµéšã«æ»ããŸãããã ããšãã°ãDBMSã§ã¯ãããŒãã«ããŒãã£ã·ã§ã³ã䜿çšããŠããã©ãŒãã³ã¹ãåäžãããããšãã§ããŸãã ãã®å ŽåãããŒãã«å šäœã§ã¯ãªãã䜿çšããããŒãã£ã·ã§ã³ã®ã¿ããããã¯ã§ããŸãïŒ https : //technet.microsoft.com/en-us/library/ms187504(v=sql.105).aspx
åé€ããã³æ¿å ¥æäœã®DBMSã§ã¯ãããŒãã«å šäœã¯éåžžããã¯ãããŠããŸããããåé€æäœã®å Žåã¯åžžã«ããã§ãã ãã ããæ¿å ¥æäœã®å ŽåãããŒã¿ãéåžžã«é«éã«ããŒãã«ã«èªã¿èŸŒãããšãã§ããŸããããã¯ãæä»çãªããŒãã«ããã¯ãäžå¯æ¬ ãªæ¡ä»¶ã§ãã
- MS SQLïŒdbcc traceonïŒ610ã-1ïŒïŒïŒINSERT INTO sales_hist WITHïŒ TABLOCKX ïŒ
- OracleïŒINSERT / * + APPEND * / INTO sales_hist
https://docs.oracle.com/cd/E18283_01/server.112/e17120/tables004.htm#i1009887
Direct-Path INSERTã®ããã¯ã«é¢ããèæ ®äºé
ãã€ã¬ã¯ããã¹INSERTäžã«ãããŒã¿ããŒã¹ã¯ããŒãã«ïŒãŸãã¯ããŒãã£ã·ã§ã³ããŒãã«ã®ãã¹ãŠã®ããŒãã£ã·ã§ã³ïŒã®æä»ããã¯ãååŸããŸãã ãã®çµæããŠãŒã¶ãŒã¯ããŒãã«ã«å¯ŸããŠåæã®æ¿å ¥ãæŽæ°ããŸãã¯åé€æäœãå®è¡ã§ããªããªããã€ã³ããã¯ã¹ã®åæäœæããã³æ§ç¯æäœã¯èš±å¯ãããŸããã ãã ããåæã¯ãšãªã¯ãµããŒããããŠããŸãããã¯ãšãªã¯æ¿å ¥æäœã®åã«æ å ±ã®ã¿ãè¿ããŸãã
ãªããªã ç§ãã¡ã®ã¿ã¹ã¯ã¯ãæéã®ãã«ãã¹ã¬ããã³ã³ãããŒãäœæããããšã§ãããã®åŸãæ¿å ¥/åé€æäœã§ã³ã³ãããŒå šäœããããã¯ããŸããã ããããä»åºŠã¯ã³ã³ããã®äžéšã®ã¿ããããã¯ããŠã¿ãŸãããã
ç¬èªã®ããŒãã£ã·ã§ã³é åºä»ãé£æ³é åpartition_mapãå®è£ ããŠãããã©ãŒãã³ã¹ãã©ãã ãåäžããããèŠãŠã¿ãŸãããã çŸåšå¿ èŠãªã»ã¯ã·ã§ã³ã®ã¿ããããã¯ããŸãã
æå³ã¯æ¬¡ã®ãšããã§ããstd:: map <safe_ptr <std :: map <>>>
ããã§ãæåã®std ::ãããã¯å®æ°ã§ãããã»ã¯ã·ã§ã³ïŒãµãããŒãã«ïŒãå«ã¿ãŸãã
ããã¯ãã»ã¯ã·ã§ã³æ°ãã³ã³ã¹ãã©ã¯ã¿ãŒã§èšå®ããããã以äžå€æŽãããªãéåžžã«åçŽåãããäŸã§ãã
åã»ã¯ã·ã§ã³ã¯ãã¹ã¬ããã»ãŒããªé£æ³é åsafe_ptr <std :: map <>>ã§ãã
æ倧ã®ããã©ãŒãã³ã¹ãåŸãã«ã¯ãã»ã¯ã·ã§ã³ã®æ°ãšãã®ç¯å²ã¯ãåã»ã¯ã·ã§ã³ã«ã¢ã¯ã»ã¹ãã確çãåãã«ãªãããã«ããå¿ èŠããããŸãã ããŒç¯å²ã0ã1000000ã§ãç¯å²ã®å é ãžã®èªã¿åã/æŽæ°/æ¿å ¥/åé€ãªã¯ãšã¹ãã®ç¢ºçãç¯å²ã®çµããããã倧ããå ŽåãããŒå€ãå°ããã»ã¯ã·ã§ã³ã¯å€§ãããç¯å²ã¯å°ããããå¿ èŠããããŸãã ããšãã°ã3ã€ã®ã»ã¯ã·ã§ã³ïŒ[0-100000]ã[100001-400000]ã[400001-1,000,000]ã
ãããããã®äŸã§ã¯ãã¯ãšãªããŒãåäžã«ååžããŠãããšä»®å®ããŸãã
ã»ã¯ã·ã§ã³ç¯å²ã¯2ã€ã®æ¹æ³ã§èšå®ã§ããŸãã
- safe_map_partitioned_t <std :: stringãint> safe_map {"a"ã "f"ã "k"ã "p"ã "u"};
safe_map_partitioned_t <intãint>ïŒ0ã100000ã10000ïŒ;
//å€0ã100000ã®å¢çãšåã»ã¯ã·ã§ã³10000ã®ã¹ããããèšå®ããŸã
ã³ã³ããã«ã¢ã¯ã»ã¹ãããšãã«ãããŒãã»ã¯ã·ã§ã³ã®å¢çãè¶ ããå Žåããªã¯ãšã¹ãã¯æãè¿ãã»ã¯ã·ã§ã³ã«ç§»åããŸã-ã€ãŸã ããã°ã©ã ã¯æ£åžžã«åäœããŸãã
äŸïŒ[42] coliru.stacked-crooked.com/a/fc148b08eb4b0580
ãŸããæ倧ã®ããã©ãŒãã³ã¹ãåŸãã«ã¯ã safe_ptr <>å ã§ä»¥åã«å®è£ ããããã³ã³ãã³ã·ã§ã³ããªãŒã®å ±æãã¥ãŒããã¯ã¹ãã䜿çšããå¿ èŠããããŸãã æå³ïŒ std :: map <contfree_safe_ptr <std :: map <>>>
åã®äŸã®ã³ãŒãã䜿çšããŠãåã®ç« ã®contfree_safe_ptrã³ãŒããè¿œå ããŸãã
眮æïŒsafe_map_partitioned_t <std :: stringãstd :: pair <std :: stringãint >>
ToïŒsafe_map_partitioned_t <std :: stringãstd :: pair <std :: stringãint>ãcontfree_safe_ptr>
äŸïŒ[43] coliru.stacked-crooked.com/a/23a1f7a3982063a1
ãã®ã¯ã©ã¹safe_map_partitioned_t <>ã¯ãã楜ãã¿ã®ããã ããã«äœæããŸããã å®éã®ããã°ã©ã ã§äœ¿çšããããšã¯æšå¥šãããŸããã äŸã瀺ããŸãã-contfree_safe_ptr <>ãã€ã³ã¿ãŒãšcontention_free_shared_mutex <>ããã¯ã«åºã¥ããŠç¬èªã®ã¢ã«ãŽãªãºã ãå®è£ ããæ¹æ³ã
䜿ãæ¹
ãŸãããªããžããªã®ã«ãŒãããsafe_ptr.hãã¡ã€ã«ãããŠã³ããŒãããŸãïŒ github.com/AlexeyAB/object_threadsafe
次ã«ããã®ãã¡ã€ã«ãcppãã¡ã€ã«ã«å«ããŸãïŒ #include "safe_ptr.h"
æé©ãªãŠãŒã¹ã±ãŒã¹ãšããŠãäžèšã®äŸ2ã«çŠç¹ãåœãŠãŸã-ã·ã³ãã«ã§çç£æ§ãé«ãïŒ
struct field_t { int money, time; field_t(int m, int t) : money(m), time(t) {} field_t() : money(0), time(0) {} }; typedef safe_obj<field_t, spinlock_t> safe_obj_field_t; // thread-safe ordered std::map by using execute around pointer idiom with contention-free shared-lock contfree_safe_ptr< std::map<int, safe_obj_field_t > > safe_map_contfree; bool success_op; switch (num_op) { case insert_op: slock_safe_ptr(test_map)->find(rnd_index); // find for pre-cache to L1 with temprorary S-lock test_map->emplace(rnd_index, field_t(rnd_index, rnd_index)); break; case delete_op: slock_safe_ptr(test_map)->find(rnd_index); // find for pre-cache to L1 with temprorary S-lock success_op = test_map->erase(rnd_index); break; case read_op: { auto s_safe_map = slock_safe_ptr(test_map); // S-lock on Table (must necessarily be) auto it = s_safe_map->find(rnd_index); if (it != s_safe_map->cend()) { auto x_field = xlock_safe_ptr(it->second); volatile int money = x_field->money; // get value x_field->money += 10; // update value } } break; default: std::cout << "\n wrong way! \n"; break; }
æ¿å ¥ãšåé€-ãããã®å€æŽ ïŒ å ±æããã¯slock_safe_ptrïŒïŒã¯å¯èœãªéãé«éã§ãããããå€æŽïŒinsert_opãŸãã¯delete_opïŒã®åã§ããfindïŒïŒæäœã®çŽåŸã«ããã¯è§£é€ãããslock_safe_ptrïŒïŒã䜿çšããŠãåé€ããå¿ èŠãããèŠçŽ ãŸãã¯æ¿å ¥ããå¿ èŠãããèŠçŽ ã«æãè¿ãèŠçŽ ãèŠã€ããŸãã ãã®æäœã®çµæãçŽæ¥äœ¿çšããããã§ã¯ãããŸãããããã®ã¢ã€ãã«æäœã¯ãåŸç¶ã®ãããå€æŽã®ããã«L1ãã£ãã·ã¥ã«ãã£ãã·ã¥ããå¿ èŠãããããŒã¿ãããã»ããµãŒã«äŒããŸãã 次ã«ãtest_map-> emplaceïŒïŒãæ¿å ¥ããããtest_map-> eraseïŒïŒãåé€ããŸãããããã®æäœã¯ãå®è¡äžã«æä»ããã¯ãèªåçã«åŒã³åºããŸãã æ¿å ¥/åé€-ã»ãŒãã¹ãŠã®ããŒã¿ãæ¢ã«ãã®ã«ãŒãã«ã®ãã£ãã·ã¥ã«ãããããããã«çºçããŸããã倧ããªãã©ã¹-å ±æããã¯ãæä»ããã¯ã«çµ¶ããå¢ããå¿ èŠã¯ãããŸããããã°ã©ã ïŒã
èªã¿åãããã³æŽæ°-ïŒãããã®èªã¿åãïŒããã³1ã€ã®èŠçŽ ã®èªã¿åããŸãã¯å€æŽ ïŒç¹å®ã®äŸã§èªã¿åãïŒread_opïŒãšåŒã¶ãã®ã¯ãããããã1ã€ã®èŠçŽ ãèªã¿åãïŒããããã1è¡ïŒå€æŽããŸãã èªã¿èŸŒãåã«ããããã«å ±æããã¯slock_safe_ptrïŒïŒã課ããä»ã®ã¹ã¬ããããããå ã®èŠçŽ ãåé€ãŸãã¯çœ®æã§ããªãããã«ããŸãã s_safe_mapãªããžã§ã¯ããååšããéãå ±æããã¯ãä¿æããç®çã®èŠçŽ ãèŠã€ããŠããã®1ã€ã®èŠçŽ ã®ã¿ã«æä»çãªxlock_safe_ptrïŒïŒããã¯ã課ãããããèªã¿åã£ãŠå€æŽããŸãã ãã®åŸãã¹ã³ãŒã{}ãé¢ãããšãx_fieldãªããžã§ã¯ããæåã«ç Žæ£ãããæä»ããã¯ãèŠçŽ ããåé€ãããŸãã次ã«ãs_safe_mapãªããžã§ã¯ããç Žæ£ãããå ±æããã¯ããããããåé€ãããŸãã
ã³ã³ãã€ã©ã䜿çšãããšãtest_mapã§ä»»æã®æäœãå®è¡ã§ããŸã-èªã¿åããŸãã¯å€æŽãããã®ã¡ãœãããåŒã³åºãããšãã§ããŸã-ãã®å Žåãæä»ããã¯ãèªåçã«é©çšãããŸãã
ãã ããã³ã³ãã€ã©ã¯ãå®æ°ãšããŠå®£èšããããªããžã§ã¯ãããŸãã¯å®æ°åç §ã«å²ãåœãŠããããªããžã§ã¯ãã®èªã¿åãã®ã¿ãèš±å¯ããŸãauto constïŒsome_ptr = test_map; ããšãã°ã some_ptr-> findïŒïŒãåŒã³åºãããšãã§ããŸãã å ±æããã¯ã¯åŒã®å®è¡æéå šäœã«èªåçã«é©çšãããŸãããäžå®ã®ãªã³ã¯ã®å Žåã次ã®
slock_safe_ptrïŒtest_mapïŒãæ瀺çã«ãããã¯ããå Žåã®åæ§ã®åäœã¯ã slock_safe_ptrïŒtest_mapïŒ-> findïŒïŒãå®è¡ã§ããŸãã ããããslock_safe_ptrïŒtest_mapïŒ-> emplaceïŒïŒãã³ã³ãã€ã«ããããšãããš; -ééãããããŸãã ãããã¯ãã¹ãŠãããã¯ã®æ£ããèªåéžæãšãã«ãã¹ã¬ããããã°ã©ã ã®æ£ããæäœãä¿èšŒããŸãã
ãã®ãã¹ãŠããã³ããã«å€ãã¯ãæåã®èšäºã§èª¬æãããŠããŸãã
ååŸããsafe_ptrå®è£ ã®ããã©ãŒãã³ã¹æ¯èŒ
äžéçµæãèŠçŽããŸããæé©åã«ããçç£æ§ãã©ãã»ã©åäžããããèŠãŠã¿ãŸãããã
ããã©ãŒãã³ã¹ã°ã©ãã¯æ¬¡ã®ãšããã§ãã1ç§ãããã®æ°çŸäžã®æäœïŒMOpsïŒã®æ°ãšãå€æŽæäœã®å²åã0ã90ïŒ ã®å Žåã§ããå€æŽäžã«ãæ¿å ¥ãåé€ãæŽæ°ã®3ã€ã®æäœã®ãããããåã確çã§å®è¡ãããŸãïŒæŽæ°æäœã§ã¯std ::ãããããªãŒèªäœã¯å€æŽãããŸããããè¡ã®1ã€ã®ã¿ãå€æŽãããŸãïŒãããšãã°ã15ïŒ ã®å€æŽãããå Žåããããã¯5ïŒ ã®æ¿å ¥ã5ïŒ ã®åé€ã5ïŒ ã®æŽæ°ã85ïŒ ã®èªã¿åããšããæäœã«ãªããŸãã䜿çšã³ã³ãã€ã©ïŒg ++ 4.9.2ïŒLinux UbuntuïŒx86_64
ãã®ãã³ãããŒã¯ã¯ãLinuxïŒGCC 4.9.2ïŒããã³WindowsïŒMSVS2015ïŒã§ããŠã³ããŒãã§ããŸãïŒgithub.com/AlexeyAB/object_threadsafe/tree/master/benchmark
Linuxã§Clang ++ 3.8.0ã§ã³ã³ãã€ã«ããã«ã¯ãMakefileãå€æŽããå¿ èŠããããŸãã
1ã€ã®ãµãŒããŒããã»ããµIntel Xeon E5-2660 v3 2.6 GHzã®16ã¹ã¬ããã§ãã¹ãããäŸã次ã«ç€ºããŸãããŸãæåã«ãå®å šãª<mapãcontfree>ïŒrowlockãšãããªã¬ã³ãžè²ã®è¡ã«èå³ããããŸãã
è€æ°ã®CPUãã€ã³ã¹ããŒã«ãããŠããå Žåãå®è¡ããã³ãã³ãã©ã€ã³ã¯æ¬¡ã®
ãšãã ã§ããnumactl --localalloc --cpunodebind = 0 ./benchmark 16
1ã€ã®CPUãã€ã³ã¹ããŒã«ãããŠããå Žåã¯ãåã«./benchmarkãå®è¡ããŸãã

çµè«ïŒ
- èå³æ·±ãããšã«ãcontfree_safe_ptr <map>ã®å ±æcontfreeããã¯ã¯ãsafe_ptr <mapãstd :: shared_mutex>ã®äžéšãšããŠã®æšæºstd :: shared_mutexãããã¯ããã«é«éã§ãã
- , 15% std::mutex , std::shared_mutex ( safe_ptr<map,std::mutex> , safe_ptr<map,std::shared_mutex>)
- , 30% std:map â 1 thread contfree_safe_ptr<map>&rowlock. . - , .
- safe_map_partitioned<,,contfree_safe_ptr>, , «Just-for-fun» â .
- 15% , shared-mutex ( contfree_safe_ptr<map> & rowlock) 8.37 Mops, 10 , std::shared_mutex ( safe_ptr<map, std::shared_mutex>), 0.74 Mops.
ã競åã®ãªãå ±æãã¥ãŒããã¯ã¹ãããã¯ã¯ãä»»æã®æ°ã®ã¹ã¬ããã§æ©èœããŸããæåã®70åã®ã¹ã¬ããã§ã¯ç«¶åãªããåŸç¶ã®ã¹ã¬ããã§ã¯æä»ããã¯ãšããŠæ©èœããŸããã°ã©ããããããããã«ããæä»ããã¯ãã®std :: mutexã§ãããstd :: shared_mutexãããé«éã§ã15ïŒ ã®å€æŽããããŸãã
ãŸããé 延ã®äžå€®å€ã®ã°ã©ãããã€ã¯ãç§åäœã§ç€ºããŸãããªã¯ãšã¹ãã®ååã«ã¯ããã®å€ããå°ããé 延ããããŸãã
main.cppãã¹ãã³ãŒãã§ã¯ã次ãèšå®ããå¿ èŠããããŸããconst bool measure_latency = true;
å®è¡ããã³ãã³ãã©ã€ã³ïŒnumactl --localalloc --cpunodebind = 0 ./benchmark 16

- èå³æ·±ãããšã«ãstd :: mapïŒstd :: mutexã¯safe_ptr <mapãstd :: mutex>ãäžå¿ã«æ¯åããŸããå šäœçã«ãsafe_ptr <>ã䜿çšããŠãäœåãªãªãŒããŒãããã¯è¿œå ããããããã©ãŒãã³ã¹ãäœäžããŸããã
- ãŸããå€æŽã®60ïŒ ãããcontfree_safe_ptr <map>ïŒrowlockãcontfree_safe_ptr <map>ãããé·ãé 延ã瀺ãããšãèå³æ·±ãã§ããããããåã®ã°ã©ããããå€æŽæäœã®å²åã«é¢ä¿ãªããcontfree_safe_ptr <map>ããã³rowlockã®å šäœçãªããã©ãŒãã³ã¹ãäŸç¶ãšããŠé«ãããšãããããŸããã
contfree_safe_ptr <std :: map>ãšãç°ãªããã¹ã¯ãããCPUäžã®CDS-libã®ã³ã³ãããŒã®ããã©ãŒãã³ã¹æ¯èŒ
ãã¹ãŠã®ã³ã¢ã䜿çšããç°ãªããã¹ã¯ãããCPUã§ã®ããã©ãŒãã³ã¹æ¯èŒã

- èå³æ·±ãããšã«ãã©ãããããããã³ãã¹ã¯ãããã®å Žåãcontfree_safe_ptr <map>ã¯ãCDS-libã®ããã¯ããªãŒãããã³ã³ãããããåªããããã©ãŒãã³ã¹ã瀺ããŸãã
- «Just-for-fun» safe_map_partitioned<,,contfree_safe_ptr> 1.7 .
contfree_safe_ptr<std::map> CDS-lib server-CPU
ç°ãªãæ°ã®ã¹ã¬ããã䜿çšããã1ã€ã®ãµãŒããŒCPUäžã®ç°ãªããã«ãã¹ã¬ããé£æ³é åã®ããã©ãŒãã³ã¹ã®æ¯èŒã
LinuxïŒGCC 4.9.2ïŒããã³WindowsïŒMSVS2015ïŒã®æ¬¡ã®ãã³ãããŒã¯ãããŠã³ããŒãã§ããŸããgithub.com/ AlexeyAB / object_threadsafe / tree / master / CDS_test
Linuxã§Clang ++ 3.8.0ã§ã³ã³ãã€ã«ããã«ã¯ãMakefileãå€æŽããå¿ èŠããããŸãã
åããã¶ãŒããŒãäžã«è€æ°ã®Xeonããã»ããµãããå Žåããã®ãã¹ãã®çµæã¯ã次ã®ããã«å®è¡ããããšã§åçŸã§ããŸã
ãnumactl --localalloc --cpunodebind = 0 ./benchmark 16
1ã€ã®CPUãã€ã³ã¹ããŒã«ãããŠããå Žåã¯ãåã«./benchmarkãå®è¡ããŸã

- , 16 , , lock-free CDS-lib , contfree_safe_ptr<map>. ã€ãŸã lock-free . 16 , 8 , contfree_safe_ptr<map> , lock-free .
- «Just-for-fun»- safe_map_partitioned<,,contfree_safe_ptr> , , .
ã¬ã€ãã³ã·ã®äžå€®å€ã¯ããªã¯ãšã¹ãã®50ïŒ ãå®è¡ãããæéãããéãæéã§ãã
main.cppãã¹ãã³ãŒãã§ã¯ã次ãèšå®ããå¿ èŠããããŸããconst bool measure_latency = true;
å®è¡ããã³ãã³ãã©ã€ã³ïŒnumactl --localalloc --cpunodebind = 0 ./benchmark 16

contfree_safe_ptr <map>ã®é 延ã®äžå€®å€ã¯ãåæã«ç«¶åããã¹ã¬ããã®æ倧8ã¹ã¬ããã®ããã¯ããªãŒã³ã³ãããŒã®é 延ãšã»ãŒåãã§ããã競åãã16ã¹ã¬ããã§ã¯æªåããŸãã
å®éã®ã¢ããªã±ãŒã·ã§ã³ã§ã®ããã©ãŒãã³ã¹ã
å®éã®ã¢ããªã±ãŒã·ã§ã³ã¯ãã¹ã¬ããéã®ããŒã¿äº€æã ãã§æ§æãããŠããããã§ã¯ãããŸãããå®éã®ã¢ããªã±ãŒã·ã§ã³ã®äž»ãªäœæ¥ã¯åã¹ã¬ããã§åå¥ã«å®è¡ããããŸãã«ããã¹ã¬ããéã§ããŒã¿ã亀æãããŸããã
ã¢ããªã±ãŒã·ã§ã³ã®å®éã®äœæ¥ãã·ãã¥ã¬ãŒãããã«ã¯ãæé©åãããŠããªãforã«ãŒããè¿œå ããŸãïŒvolatile int i = 0; i <9000; ++ iïŒ;ã¹ã¬ããã»ãŒãã³ã³ãããžã®ååŒã³åºãã®éããã¹ãã®éå§æã«ããã®ãµã€ã¯ã«ã100,000åå®è¡ãããã®ãµã€ã¯ã«ãå®äºããã®ã«ãããå¹³åæéã枬å®ããŸãã Intel Xeonããã»ããµE5-2686 v4 2.3 GHzã§ã¯ããã®å®éã®äœæ¥ã®ã·ãã¥ã¬ãŒã·ã§ã³ã«ã¯çŽ20.5ãã€ã¯ãç§ããããŸãã
LinuxïŒGCC 4.9.2ïŒããã³WindowsïŒMSVS2015ïŒã®ãã®ãã³ãããŒã¯ã¯ã次ã®ãªã³ã¯ããããŠã³ããŒãã§ããŸããgithub.com/ AlexeyAB / object_threadsafe / tree / master / Real_app_bench
Linuxã§Clang ++ 3.8.0ã§ã³ã³ãã€ã«ããã«ã¯ãMakefileãå€æŽããå¿ èŠããããŸãã
2ããã»ããµãµãŒããŒã§ãã¹ãããŸãïŒ2 x Intel Xeon E5-2686 v4 2.3 GHzïŒBroadwellïŒãåèšã³ã¢æ°ïŒ36ç©çã³ã¢ãš72è«çã³ã¢ïŒãã€ããŒã¹ã¬ããã£ã³ã°ïŒã
ã³ã³ãã€ã«ããŠå®è¡ããã«ã¯ã次ãå®è¡ããŸãã
cd libcds
äœã
cd ...
äœã
./benchmark

- æšæºstd :: mutexããã³std :: shared_mutexãã¥ãŒããã¯ã¹ã䜿çšããŠstd :: mapãä¿è·ãããšãæ倧16ã¹ã¬ããã®ããã¯ããªãŒãããã³ã³ãããŒã«è¿ãããã©ãŒãã³ã¹ãæäŸãããŸãããããããã®åŸãstd :: mutexïŒstd :: mapããã³std :: shared_mutexïŒstd :: mapã®ããã©ãŒãã³ã¹ã¯é ãå§ãã32åã®ã¹ã¬ãããäœäžãå§ããŸãã
- æé©åãããã¹ã¬ããã»ãŒããã€ã³ã¿ãŒcontfree_safe_ptr <std :: map <>>ã䜿çšãããšã1ã64ã®ä»»æã®æ°ã®ã¹ã¬ããã§libCDSã©ã€ãã©ãªã®ããã¯ããªãŒãããã³ã³ãããŒã®ããã©ãŒãã³ã¹ãšã»ãŒåçã®ããã©ãŒãã³ã¹ãåŸãããŸãããããŒéã®äº€æã¯ãå¹³åã§20ãã€ã¯ãç§ä»¥äžã«1åè¡ãããŸãã
é 延ã®äžå€®å€ã枬å®ããã«ã¯ãmain.cppãã¹ãã³ãŒãã§ä»¥äžãèšå®ããå¿ èŠããããŸããconst bool measure_latency = true;
Linuxã§å®è¡ããã«ã¯ã次ã®ããã«å ¥åããŸãã./benchmark

- èå³æ·±ãããšã«ã64ã¹ã¬ããã§ã¯ãstd :: mutexã¯std :: shared_mutexãããããã©ãŒãã³ã¹ãšã¡ãã£ã¢ã³é 延ã®äž¡æ¹ã倧ãããªããŸãã
- - contfree_safe_ptr<std::map<>> lock-free-map libCDS 1 64. , 20 .
- 64 30 , 20 â , 10 â . , 30% , contfree_safe_ptr<T> (MOPS -), lock-free libCDS.
libCDSã®ããåçŽãªããã¯ããªãŒããã³åŸ æ©ããªãŒã®ã³ã³ããïŒãã¥ãŒãã¹ã¿ãã¯...ïŒã¯ãããã¯ã®å®è£ ãããé 延ãé¡èã«å°ãªããªã£ãŠããŸãã
çµè«ïŒ
- åãã³ã³ããã§ãããŒã®ç«¶åãæ¿ããå Žåãã€ãŸã ããæç¹ã§ãå¹³åã§8åãè¶ ããã¹ã¬ãããã³ã³ããã«ã¢ã¯ã»ã¹ããå Žåãæè¯ã®è§£æ±ºçã¯CDSlibã©ã€ãã©ãªã®ã³ã³ããã䜿çšããããšã§ãïŒgithub.com/khizmax/libcds
- å¿ èŠãªã¹ã¬ããã»ãŒãã³ã³ãããCDSlibã«ããå Žåã¯ãããã䜿çšããŸãã
- ããã°ã©ã ãã¹ããªãŒã éã§ããŒã¿ã亀æãã以å€ã«äœããè¡ããã¹ããªãŒã éã§äº€æããã®ã«åèšæéã®30ïŒ ããããããªãå Žåãæ°ååã®ã¹ããªãŒã ã䜿çšããŠããcontfree_safe_ptr <>ãã€ã³ã¿ãŒã¯CDSlibã®ãããã³ã³ãããŒããé«éã§ãã
- , CDSlib, contfree_safe_ptr<T> . , lock-free .
ãããã®èšäºã§ã¯ãExecute Around Pointer Idiomã®äŸã䜿çšããŠãåäžã¹ã¬ããã§ã®C ++èšèªæ§é ã®å®è¡ã·ãŒã±ã³ã¹ã詳现ã«èª¿ã¹ãŸããããŸãã競åã®ãªãå ±æãã¥ãŒããã¯ã¹ã®äŸã䜿çšããŠããã«ãã¹ã¬ããããã°ã©ã ã§ã®èªã¿åãããã³æžã蟌ã¿æäœã®ã·ãŒã±ã³ã¹ã調ã¹ãŸããããŸããlibCDSã®ããã¯ããªãŒã¢ã«ãŽãªãºã ãšãåœç€Ÿãéçºããããã¯ããŒã¹ã¢ã«ãŽãªãºã ã®é«æ§èœãªäœ¿çšäŸã瀺ããŸããã
ãã®çµæãsafe_ptr.hãã¡ã€ã«ãããŠã³ããŒãã§ããŸãããã®ãã¡ã€ã«ã«ã¯ã次ã®èšäºã§äœæããããã¹ãŠã®ã¯ã©ã¹ãšé¢æ°ãå«ãŸããŠããŸããgithub.com / AlexeyAB / object_threadsafe
ããŒã¹ãã©ã€ãã©ãªã®äžéšãšããŠãèšäºã§åæãããã¢ã«ãŽãªãºã ãä¿®æ£ãã圢åŒã§è¡šç€ºããŸããïŒ