ã¢ãã³ç¬¬5ç« ïŒãC++11/14ãæšæºãã«ãã¹ã¬ãããšäžŠè¡åŠç
std::threadã»æä»å¶åŸ¡ïŒmutex/lock_guardïŒã»ããŒã¿ç«¶åã®æ²æ»
ãšstd::atomic
çŸä»£ã®ãã¹ãŠã®CPUã¯ãã«ãã³ã¢ïŒ8ã³ã¢ã16ã³ã¢ïŒãåœããåã§ããã1æ¬ã®ã¡ã€ã³ã¹ã¬ããã ãã§ã²ãŒã ãé«è² è·ã·ã¹ãã ãåããã®ã¯CPUãªãœãŒã¹ã®å€§åãããã«æšãŠããããªãã®ã§ãããããããã€ãŠã®C++03æä»£ã¯èšèªä»æ§ã«ã¹ã¬ããã®æŠå¿µãååšãããOSäŸåã®æ³¥èãAPIïŒPOSIX pthreadsãWin32 APIïŒãçŽæ¥å©ããªããã°ãªããŸããã§ãããC++11ã§åããŠèšèªä»æ§ãšããŠçµã¿èŸŒãŸãããæšæºã¹ã¬ããã©ã€ãã©ãªïŒstd::threadïŒããšãã¡ã¢ãªã¢ãã«ãã¯ãã¯ãã¹ãã©ãããã©ãŒã ã§å®å
šã»é«éãªäžŠè¡åŠçãžã®æãéããŸãããæ¬ç« ã§ã¯ãéåæã¿ã¹ã¯ã®èµ·åã»åŸ
æ©ïŒjoin / detachïŒãããæªå®çŸ©åäœãåŒãèµ·ãããããŒã¿ç«¶åïŒData RaceïŒãã®ã¡ã«ããºã ãRAIIã«ããæä»å¶åŸ¡ïŒstd::mutex, std::lock_guardïŒããããŠæ¥µéã®äœãªãŒããŒããããå®çŸãããããã¯ããªãŒååçæäœïŒstd::atomicïŒããŸã§ã培åºè§£èª¬ããŸãã
M5.1 OSäŸåã¹ã¬ããAPIã®çµçïŒC++11æšæºã¡ã¢ãªã¢ãã«ã®é©åœ
pthreadãWin32ããè±åŽãããªãèšèªä»æ§ã¬ãã«ã§ã¹ã¬ãããå®çŸ©ãããå¿
èŠããã£ãã®ãã解説ããŸãã
ð§ ãã³ã®ã³å
茩
ã·ãã¯ãå
çïŒã¹ããŒãžåãæ¿ãæã«è£ã§BGMãæµãã¯ã¹ãã£ãéåæããŒãããããšããããWindowsã§ã¯ CreateThreadãMacãLinuxã§ã¯ pthread_create ãæžããã°ãªããã#ifdef å°çã§ã³ãŒããççºããŸããâŠïŒ
ð»ââïž ã·ãã¯ãå
ç
ãµãã£ãµãã£ãµãïŒC++03ãŸã§ã¯ãäžçã¯ã·ã³ã°ã«ã¹ã¬ããã§åããã®ããšããŠèŠæ ŒãäœãããŠãã£ãããã®ãããã«ãã¹ã¬ããã¯ãã¹ãŠOSç¬èªã®æ¡åŒµæ©èœã«é Œããããªãã£ãã®ããã
ð§ ãã³ã®ã³å
茩
C++11ã§æšæºã©ã€ãã©ãªã« std::thread ãå
¥ã£ãŠãäœãå€ãã£ããã§ããïŒ
ð»ââïž ã·ãã¯ãå
ç
OSã®å·®åãå®å
šã«æ¶æ»
ããã ãã§ãªããèšèªèŠæ ŒãšããŠãã¡ã¢ãªã¢ãã«ïŒå€æ°ãžã®èªã¿æžãã®é åºä¿èšŒïŒãã峿 Œã«å®çŸ©ãããã®ããïŒã©ã®OSã»ã©ã®CPUïŒx86/ARMïŒã§ããæ±ºå®è«çã§å®å
šãªäžŠè¡åŠçãæžããããã«ãªã£ãã®ãããïŒ
M5.2 ããŒã¿ç«¶åïŒData RaceïŒã®ææãš std::lock_guard ã«ããRAIIæä»å¶åŸ¡
è€æ°ã®ã¹ã¬ãããåæã«åã倿°ãæŽæ°ããç¬éã«èµ·ããç Žæ»
ãšããããããã¯ãé²ãRAIIããã¯ã®ä»çµã¿ãåŠã³ãŸãã
ð§ ãã³ã®ã³å
茩
å
çïŒ2ã€ã®ã¹ã¬ããããã¹ã³ã¢å€æ° g_score ã«ãããã 1000åã〠+1 å ç®ããã®ã«ãèšç®çµæã 2000 ã§ã¯ãªã 1432 ãšãå€ãªæ°åã«ãªããŸãïŒ
ð»ââïž ã·ãã¯ãå
ç
ããããã䞊è¡åŠçæå€§ã®éç©ãããŒã¿ç«¶åïŒData Race / ã¬ãŒã¹ã³ã³ãã£ã·ã§ã³ïŒãããïŒg_score++ ã¯1åœä»€ã§ã¯ãªãããCPUã¬ãžã¹ã¿ã«èªã¿èŸŒãããå ç®ããããã¡ã¢ãªã«æžãæ»ãããšãã3ã¹ããããããããéäžã§å¥ã¹ã¬ããã«å²ã蟌ãŸããŠå€ãäžæžãæ¶æ»
ããã®ããïŒ
M5.3 å®è£
ç·šïŒstd::atomic ã«ããããã¯ããªãŒé«éã«ãŠã³ã¿ãšã¹ã¬ããåŠç
éããã¥ãŒããã¯ã¹ãåé¿ããCPUã®ããŒããŠã§ã¢ã¢ãããã¯åœä»€ã§è¶
é«éã«åäœããã«ãŠã³ã¿ãå®è£
ããŸãã
ð ThreadSafeCounter.cpp
#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
#include <atomic>
// 1. ãã¥ãŒããã¯ã¹ã«ããæä»å¶åŸ¡
int g_mutexCounter = 0;
std::mutex g_mtx;
void incrementWithMutex(int count) {
for (int i = 0; i < count; ++i) {
std::lock_guard<std::mutex> lock(g_mtx); // RAIIããã¯
g_mutexCounter++;
}
}
// 2. std::atomic ã«ããããã¯ããªãŒååçå ç®ïŒCPUåœä»€ã¬ãã«ã®æä»ïŒ
std::atomic<int> g_atomicCounter(0);
void incrementWithAtomic(int count) {
for (int i = 0; i < count; ++i) {
g_atomicCounter.fetch_add(1); // ãŸãã¯åã« g_atomicCounter++
}
}
int main() {
const int THREAD_COUNT = 4;
const int ITERATIONS = 10000;
std::cout << "=== 1. std::mutex ã«ãã䞊è¡åŠç ===" << std::endl;
std::vector<std::thread> threads1;
for (int i = 0; i < THREAD_COUNT; ++i) {
threads1.push_back(std::thread(incrementWithMutex, ITERATIONS));
}
for (size_t i = 0; i < threads1.size(); ++i) {
threads1[i].join(); // å
šã¹ã¬ããçµäºåŸ
æ©
}
std::cout << "Mutexçµæ: " << g_mutexCounter << " (æåŸ
å€: " << (THREAD_COUNT * ITERATIONS) << ")" << std::endl;
std::cout << "\n=== 2. std::atomic ã«ããããã¯ããªãŒåŠç ===" << std::endl;
std::vector<std::thread> threads2;
for (int i = 0; i < THREAD_COUNT; ++i) {
threads2.push_back(std::thread(incrementWithAtomic, ITERATIONS));
}
for (size_t i = 0; i < threads2.size(); ++i) {
threads2[i].join();
}
std::cout << "Atomicçµæ: " << g_atomicCounter.load() << " (æåŸ
å€: " << (THREAD_COUNT * ITERATIONS) << ")" << std::endl;
return 0;
}
ð¡ ãã®ã»ã¯ã·ã§ã³ã®éèŠãã€ã³ã
- C++11æšæºã¹ã¬ããã®æ©æµ: OSäŸåã³ãŒããå®å
šã«æé€ããstd::thread ãšã©ã ãåŒã§åå®å
šã»ããŒã¿ãã«ãªäžŠè¡åŠçãå®çŸããã
- ããŒã¿ç«¶åã¯æªå®çŸ©åäœ: è€æ°ã¹ã¬ãããåæãªãã§å
±æå€æ°ãæžãæãããšã¡ã¢ãªãç Žæãããå¿
ã mutex ã atomic ãä»ããã°ãªããªãã
- RAIIããã¯ã®åŸ¹åº: ç mutex.lock() ã¯äœ¿ãããåžžã« std::lock_guard ãŸã㯠std::unique_lock ã䜿çšããŠäŸå€çºçæã®ã¢ã³ããã¯æŒããé²ãã
- std::atomic ã®åšå: åäžæŽæ°ã®ã€ã³ã¯ãªã¡ã³ãããã©ã°æŽæ°ã«ã¯ãOSã®ã³ã³ããã¹ãã¹ã€ããã䌎ããªãããã¯ããªãŒååçæäœïŒstd::atomicïŒãæéã
ð ç解床ãã§ãã¯ã¯ã€ãº
Q1. C++11ã® `std::thread` ãªããžã§ã¯ããç Žæ£ããéãjoin() ã detach() ãåŒã°ããŠããªãå Žåã«çºçããé倧ãªåäœã¯ã©ãã§ããïŒ
- 1. è£ã§åæã«ã¹ã¬ãããçµäºãããŸã§éãã«åŸ
æ©ãã
- 2. std::terminate() ã匷å¶çã«åŒã³åºãããããã°ã©ã å
šäœãå³åº§ã«ç°åžžçµäºïŒã¯ã©ãã·ã¥ïŒãã
- 3. ã³ã³ãã€ã«ãšã©ãŒã«ãªã
- 4. ã¹ã¬ãããèªåçã« detach ãããŠOSã«åŒãæž¡ããã
æ£è§£ãšè§£èª¬ãèŠã
æ£è§£ïŒstd::terminate() ã匷å¶çã«åŒã³åºãããããã°ã©ã å
šäœãå³åº§ã«ç°åžžçµäºïŒã¯ã©ãã·ã¥ïŒãã
C++èŠæ Œã§ã¯ãjoinable ãªç¶æ
ïŒjoin ã detach ããããŠããªãïŒã® std::thread ã®ãã¹ãã©ã¯ã¿ãèµ°ããšãå®å
šã®ããåçç¡çšã§ std::terminate() ãåŒã°ããããã»ã¹ã峿ã¢ããŒãããŸãã
Q2. ãã¥ãŒããã¯ã¹ã®ããã¯ã« `std::lock_guard<std::mutex>` ã䜿çšããæå€§ã®ã¡ãªããã¯äœã§ããïŒ
- 1. ããã¯ã®åŠçé床ã10åéããªããã
- 2. ã¹ã³ãŒããæããéãéäžã§äŸå€ãã¹ããŒãããå Žåã§ãããã¹ãã©ã¯ã¿ã«ãã確å®ã« unlock() ãåŒã³åºãããããããã¯ãé²ããã
- 3. è€æ°ã®ãã¥ãŒããã¯ã¹ã1ã€ã®å€æ°ã§åæã«æäœã§ãããã
- 4. ã¡ã¢ãªäœ¿çšéããŒãã«ãªããã
æ£è§£ãšè§£èª¬ãèŠã
æ£è§£ïŒã¹ã³ãŒããæããéãéäžã§äŸå€ãã¹ããŒãããå Žåã§ãããã¹ãã©ã¯ã¿ã«ãã確å®ã« unlock() ãåŒã³åºãããããããã¯ãé²ããã
std::lock_guard 㯠RAIIïŒResource Acquisition Is InitializationïŒã®å
žåäŸã§ãããæ§ç¯æã« lock() ãç Žæ£æã«å¿
ã unlock() ãåŒã³åºãããã颿°ã®éäžã§ return ãããäŸå€ãé£ãã§ãã¢ã³ããã¯æŒããçºçããŸããã
Q3. æŽæ°ã«ãŠã³ã¿ã®äžŠè¡å ç®ã«ãããŠã`std::mutex` ã§ã¯ãªã `std::atomic<int>` ãéžã¶äž»ãªå©ç¹ã¯äœã§ããïŒ
- 1. atomic ã䜿ããšã«ãŠã³ã¿ãç¡é倧ãŸã§æ±ããããã«ãªããã
- 2. OSã®ã«ãŒãã«åŒã³åºããã¹ã¬ããäŒæ¢ïŒã³ã³ããã¹ãã¹ã€ããïŒã䌎ãããCPUã®ååçããŒããŠã§ã¢åœä»€ã§è¶
é«éã«å ç®ã§ãããã
- 3. atomic ã¯C++03ã§ãå©çšå¯èœãªãã
- 4. atomic 倿°ã¯ã¹ã¿ãã¯ã¡ã¢ãªãäžåæ¶è²»ããªããã
æ£è§£ãšè§£èª¬ãèŠã
æ£è§£ïŒOSã®ã«ãŒãã«åŒã³åºããã¹ã¬ããäŒæ¢ïŒã³ã³ããã¹ãã¹ã€ããïŒã䌎ãããCPUã®ååçããŒããŠã§ã¢åœä»€ã§è¶
é«éã«å ç®ã§ãããã
std::atomic ã¯CPUã®ããã¯ãã¬ãã£ãã¯ã¹åœä»€ïŒLOCK XADDãªã©ïŒã«çŽæ¥ã³ã³ãã€ã«ãããããããã¥ãŒããã¯ã¹ã®ãããªéãOSã«ãŒãã«åæãã¹ã¬ããã®ãããã¯ã»ãŠã§ã€ã¯ã¢ããã®ãªãŒããŒããããªãã«æé«éã§åäœããŸãã
ð»ââïž ã·ãã¯ãC++ã©ã ã€ã³ã¿ã©ã¯ãã£ãåŠç¿ã·ã¹ãã
ãã©ãŠã¶ã§JavaScriptãæå¹ã«ãããšããã©ãŠã¶å
ã€ã³ããŒããŒã²ãŒã ãšãã¥ã¬ãŒã¿ãã¡ã¢ãªãããå¯èŠåãUMLã¯ã©ã¹å³ã察話å解説ãç解床ã¯ã€ãºãèµ·åããŸãã
ã€ã³ã¿ã©ã¯ãã£ãåŠç¿ãéå§ãã â