ã³ãŒãèªè§£æŒç¿ Step 4ãçŸå ŽéèãïŒéåæã»ãã«ãã¹ã¬ããç«¶åã³ãŒãã®èªè§£è¡
ããŸã«ããåçŸããªãã¯ã©ãã·ã¥ã»ã¬ãŒã¹ã³ã³ãã£ã·ã§ã³ã»ãããããã¯ã®æœäŒç®æãéçã¹ãã£ã³ã§æŽã
ããã¹ãç°å¢ã§ã¯100%åãã®ã«ãæ¬çªãµãŒããŒãé«è² è·æã ãããŸã«è¬ã®ã¯ã©ãã·ã¥ããããââãããããéçºè
ãæãèŠããã䞊è¡åŠçã®ãã°ïŒHeisenbugïŒã§ããæä»å¶åŸ¡ïŒstd::mutexïŒã®ããã¯ç¯å²ãè€æ°ãã¥ãŒããã¯ã¹ã®ç²åŸé åºãstd::atomic ã®äœ¿ããæ¹ãã³ãŒãããèªã¿è§£ããã¬ãŒã¹ã³ã³ãã£ã·ã§ã³ããããããã¯ã®æœäŒç®æãæŽãããã®éèçŒã逿ããŸãã
4.1 䞊è¡åŠçèªè§£ã®éåïŒãå
±æããŒã¿ããšãã¢ã¯ã»ã¹ãã¹ãã®äº€å·®ç¹ãçãåºã
ãã«ãã¹ã¬ããã³ãŒããæŒ«ç¶ãšèªãã§ã¯ãããŸããããå
±æãããå¯å€ããŒã¿ããç¹å®ããä¿è·ã®ç¶²çŸ
æ§ãšããã¯é åºãç£æ»ããŸãã
ð§ ãã³ã®ã³å
茩
ã·ãã¯ãå
çïŒå
èŒ©ãæžããã¯ãŒã«ãŒã¹ã¬ããã®ã¿ã¹ã¯åŠçã³ãŒãã§ãã1000åã«1åããããã¥ãŒã®äžèº«ãå£ããŠèœã¡ãããšããæããããã°ã®èª¿æ»ãé ŒãŸããŸããïŒãããã¬ãç¹ãã§ãåçŸããªããŠéæ¹ã«æ®ããŠããŸãâŠâŠïŒ
ð»ââïž ã·ãã¯ãå
ç
ãµãã£ãµãã£ãµãïŒèгå¯ããããšãããšçŸè±¡ãæ¶ãããåé«ãããã€ãŒã³ãã°ïŒHeisenbugïŒããããªïŒäžŠè¡åŠçã®ãã°ã¯åçãããã°ã ãã«é Œã£ãŠã¯ãªãã¬ãã³ãŒããéçã«çºãã**ãâ è€æ°ã¹ã¬ãããè§Šãå
±æå€æ°ã¯ã©ãããâãâ¡ ãã¹ãŠã®ã¢ã¯ã»ã¹ã§ mutex ãæ¡ãããŠããããâãâ¢ è€æ°ãã¥ãŒããã¯ã¹ã®ååŸé åºãäžå®ãã**ã®3ååã§éçã«æŽãåºãã®ããïŒ
### 䞊è¡åŠçã³ãŒãéèã®ã3倧ã¹ãã£ã³ã»ãã§ãã¯ãªã¹ãã
1. **ãã§ãã¯1ïŒå
±æå¯å€ç¶æ
ïŒShared Mutable StateïŒã®ç¹å®**:
- ã©ã®ã¡ã³ã倿°ãè€æ°ã¹ã¬ããããèªã¿æžãããããïŒïŒãã¥ãŒãã«ãŠã³ã¿ãå®äºãã©ã°ãªã©ïŒ
- ãèªã¿åãïŒReadïŒãã ãããšãã£ãŠ mutex ãªãã§ã¢ã¯ã»ã¹ããŠããªããïŒïŒæžã蟌ã¿äžã®èªã¿åããç«æŽŸãªããŒã¿ç«¶åïŒ
2. **ãã§ãã¯2ïŒããã¯ç²åŸé åºïŒLock Acquisition OrderïŒã®çµ±äž**:
- 颿°Aã§ `Lock(M1) -> Lock(M2)` ã®é ã§åã£ãŠããã®ã«ã颿°Bã§ `Lock(M2) -> Lock(M1)` ãšéé ã§åã£ãŠããªããïŒïŒãããããã¯ã®ç¢ºå®ãã©ã°ïŒ
3. **ãã§ãã¯3ïŒåæããªããã£ãã®æ£åœæ§**:
- `std::condition_variable` ãåŒã¶éã`while` ã«ãŒãã§æ¡ä»¶ãå確èªããŠãããïŒïŒã¹ããªã¢ã¹ã»ãŠã§ã€ã¯ã¢ãã察çïŒ
- `std::atomic` ã«é ŒããããŠãè€æ°å€æ°ã®ã¢ãããã¯æ§ã厩ããŠããªããïŒ
ð¡ ãã®ã»ã¯ã·ã§ã³ã®éèŠãã€ã³ã
- ãèªã¿åãå°çšã ããããã¯äžèŠãã¯æå€§ã®å¹»æ³: C++ã®ã¡ã¢ãªã¢ãã«ã«ãããŠãçæ¹ã®ã¹ã¬ãããæžã蟌ãã§ããæäžã«å¥ã®ã¹ã¬ãããéããã¯ã§èªã¿åºããšãæªå®çŸ©åäœïŒUndefined BehaviorïŒããšãªããå€ã®ç Žæãã¯ã©ãã·ã¥ãå¿
çºããŸãã
4.2 æŒç¿ã³ãŒãïŒéåæã¿ã¹ã¯åŠçãããŒãžã£ãŒïŒAsyncJobQueueïŒ
以äžã®C++ã³ãŒãã«ã¯ãçŸå Žã§é »çºãããæ·±å»ãªäžŠè¡åŠçãã°ã3ç®æãæœãã§ããŸãããã£ããèªã¿è§£ããŠãã ããã
ð AsyncJobQueue.h
#include <iostream>
#include <vector>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
struct Job {
int id;
std::string payload;
};
class AsyncJobQueue {
private:
std::queue<Job> m_queue;
std::mutex m_queueMutex;
std::mutex m_logMutex;
std::condition_variable m_cv;
bool m_isRunning = true;
int m_processedCount = 0; // åŠçæžã¿ãžã§ãæ°
public:
// ãžã§ãã®è¿œå ïŒã¡ã€ã³ã¹ã¬ããããåŒã°ããïŒ
void pushJob(Job job) {
{
std::lock_guard<std::mutex> lock(m_queueMutex);
m_queue.push(std::move(job));
}
m_cv.notify_one();
}
// ã¯ãŒã«ãŒã¹ã¬ããã®ã¡ã€ã³ã«ãŒã
void workerLoop(int workerId) {
while (m_isRunning) {
Job currentJob;
{
std::unique_lock<std::mutex> qLock(m_queueMutex);
m_cv.wait(qLock, [this]() { return !m_queue.empty() || !m_isRunning; });
if (!m_isRunning && m_queue.empty()) {
break;
}
currentJob = std::move(m_queue.front());
m_queue.pop();
}
// ãžã§ãã®å®è¡
executeJob(workerId, currentJob);
// â ïž çåç¹AïŒæä»å¶åŸ¡ã®ãªãã«ãŠã³ã¿å ç®ïŒ
m_processedCount++;
}
}
// ãžã§ãå®è¡ïŒãã°åºåä»ãïŒ
void executeJob(int workerId, const Job& job) {
// â ïž çåç¹BïŒããã¯é åºã¯å®å
šãïŒ
std::lock_guard<std::mutex> logLock(m_logMutex);
std::cout << "[Worker " << workerId << "] Job " << job.id << " executed: " << job.payload << std::endl;
}
// ãžã§ããã¥ãŒã®çµ±èšãã³ã
void dumpStats() {
// â ïž çåç¹CïŒm_logMutex ãåã£ãåŸã« m_queueMutex ãåãïŒ
std::lock_guard<std::mutex> logLock(m_logMutex);
std::lock_guard<std::mutex> qLock(m_queueMutex);
std::cout << "=== Queue Stats ===" << std::endl;
std::cout << "Remaining: " << m_queue.size() << ", Completed: " << m_processedCount << std::endl;
}
// åŠçæžã¿ä»¶æ°ã®ååŸ
int getProcessedCount() const {
return m_processedCount; // â ïž çåç¹DïŒããã¯ãªãã§çŽæ¥èªããã®ãïŒ
}
void stop() {
{
std::lock_guard<std::mutex> lock(m_queueMutex);
m_isRunning = false;
}
m_cv.notify_all();
}
};
ð¡ ãã®ã»ã¯ã·ã§ã³ã®éèŠãã€ã³ã
- ã³ãŒãã¬ãã¥ãŒæã®èŠç·ã®åããæ¹: ãŸãã¡ã³ã倿°äžèЧãèŠãŠããã¥ãŒããã¯ã¹ã®æ°ãã確èªããŸãã2å以äžã®ãã¥ãŒããã¯ã¹ãããå Žåãå¿
ããè€æ°åæã«ããã¯ããŠããç®æããæ¢ããŠé åºã®äžäžèŽïŒAB-BAãããããã¯ïŒãçããŸãã
4.3 éèææ»ïŒæœäŒããŠãã3å€§æ¬ é¥ã®è§£èª¬
ããã®éèçŒãç¹å®ãããããŒã¿ç«¶åãããããããã¯ããéä¿è·èªã¿åºããã®å
šè²ã§ãã
ð ç解床ãã§ãã¯ã¯ã€ãº
Q1. AsyncJobQueue ã«ãããŠãè€æ°ã¹ã¬ããããåæã«å®è¡ãããéã«ãããŒã¿ç«¶åïŒData RaceïŒããçºçããŠæªå®çŸ©åäœãšãªã倿°ã¯ã©ãã§ãããïŒ
- 1. m_queueïŒstd::queueïŒ
- 2. m_processedCountïŒintïŒ
- 3. m_queueMutexïŒstd::mutexïŒ
- 4. m_cvïŒstd::condition_variableïŒ
æ£è§£ãšè§£èª¬ãèŠã
æ£è§£ïŒm_processedCountïŒintïŒ
æ£è§£ã§ãïŒm_processedCount ã¯éåžžã® int ã§ãããworkerLoop å
ã§ããã¯ãªãã« `m_processedCount++` ãããŠããŸããè€æ°ã¹ã¬ãããåæã«ã€ã³ã¯ãªã¡ã³ããããšç«¶åïŒData RaceïŒãçºçããŸãã
Q2. è€æ°ã¹ã¬ããéã§ããããããã¯ïŒDeadlockïŒããçºçããæ ¹æ¬çãªåå ã¯äœã§ãããïŒ
- 1. ã¹ã¬ããã®æ°ãå€ãããããš
- 2. è€æ°ã®ãã¥ãŒããã¯ã¹ãç²åŸããé åºãã颿°ãã¹ã¬ããããšã«ç°ãªã£ãŠãããäºãã«çžæã®ããã¯è§£æŸãåŸ
ã¡åã£ãŠããŸãããš
- 3. std::lock_guard ã§ã¯ãªã std::unique_lock ã䜿ã£ãŠããããš
- 4. while ã«ãŒãã䜿ã£ãŠããããš
æ£è§£ãšè§£èª¬ãèŠã
æ£è§£ïŒè€æ°ã®ãã¥ãŒããã¯ã¹ãç²åŸããé åºãã颿°ãã¹ã¬ããããšã«ç°ãªã£ãŠãããäºãã«çžæã®ããã¯è§£æŸãåŸ
ã¡åã£ãŠããŸãããš
æ£è§£ã§ãïŒäŸãã°ã¹ã¬ããAã M1 ãåã£ãŠãã M2 ãåŸ
ã£ãŠããéã«ãã¹ã¬ããBã M2 ãåã£ãŠãã M1 ãåŸ
ã€ãšãæ°žä¹
ã«ãäºããé²ãŸãªããªãã埪ç°åŸ
ã¡ïŒãããããã¯ïŒããçºçããŸãã
Q3. m_processedCount ã«å¯ŸããããŒã¿ç«¶åãè§£æ¶ããããã®ãæãã·ã³ãã«ãã€ãªãŒããŒãããã®äœãC++æšæºã®ä¿®æ£æ¹æ³ã¯ã©ãã§ãããïŒ
- 1. volatile int m_processedCount ã«å€æŽãã
- 2. std::atomic<int> m_processedCount = 0; ã«å€æŽãã
- 3. ãã¹ãŠã®ã¹ã¬ãããã·ã³ã°ã«ã¹ã¬ããã«ãã
- 4. sleep_for(1ms) ãã€ã³ã¯ãªã¡ã³ãã®åã«å
¥ãã
æ£è§£ãšè§£èª¬ãèŠã
æ£è§£ïŒstd::atomic<int> m_processedCount = 0; ã«å€æŽãã
æ£è§£ã§ãïŒC++ã«ãã㊠volatile ã¯ã¹ã¬ããå®å
šæ§ãä¿èšŒããŸããã`std::atomic<int>` ã䜿çšããããšã§ãããŒããŠã§ã¢ã®ååçåœä»€ïŒCPUã¢ãããã¯å ç®ïŒã«ããããã¯äžèŠãã€æé«éã§ããŒã¿ç«¶åãå®å
šæé€ã§ããŸãã
Q4. `m_cv.wait(qLock, [this]() { return !m_queue.empty() || !m_isRunning; });` ã§ã©ã ãåŒã«ããæ¡ä»¶è¿°èªãæž¡ããŠããçç±ïŒã¹ããªã¢ã¹ã»ãŠã§ã€ã¯ã¢ãã察çïŒã¯äœã§ãããïŒ
- 1. OSã®éœåã§ notify ãããŠããªãã®ã«ã¹ã¬ãããåæã«ç®èŠããŠããŸãçŸè±¡ããããããæ¡ä»¶ãçã«ãªããŸã§èªåã§ååŸ
æ©ããããã
- 2. ã³ã³ãã€ã«ãšã©ãŒãé²ãããã®åœ¢åŒçãªããŸããªã
- 3. ã¡ã¢ãªãç¯çŽãããã
- 4. 颿°ã®å®è¡é床ã2åã«ãããã
æ£è§£ãšè§£èª¬ãèŠã
æ£è§£ïŒOSã®éœåã§ notify ãããŠããªãã®ã«ã¹ã¬ãããåæã«ç®èŠããŠããŸãçŸè±¡ããããããæ¡ä»¶ãçã«ãªããŸã§èªåã§ååŸ
æ©ããããã
æ£è§£ã§ãïŒãã«ãã¹ã¬ããç°å¢ã§ã¯ãOSã®ã·ã°ãã«é
éã®éœåãªã©ã§éç¥ããªãã®ã«èµ·ããŠããŸããã¹ããªã¢ã¹ã»ãŠã§ã€ã¯ã¢ããïŒèåœã®èµ·åºïŒããèµ·ããŸããè¿°èªãæž¡ãããšã§ãæ¡ä»¶ãæºãããŠããªãå Žåã¯èªåçã«åã¹ãªãŒãã«å
¥ããã°ãé²ããŸãã
ð»ââïž ã·ãã¯ãC++ã©ã ã€ã³ã¿ã©ã¯ãã£ãåŠç¿ã·ã¹ãã
ãã©ãŠã¶ã§JavaScriptãæå¹ã«ãããšããã©ãŠã¶å
ã€ã³ããŒããŒã²ãŒã ãšãã¥ã¬ãŒã¿ãã¡ã¢ãªãããå¯èŠåãUMLã¯ã©ã¹å³ã察話å解説ãç解床ã¯ã€ãºãèµ·åããŸãã
ã€ã³ã¿ã©ã¯ãã£ãåŠç¿ãéå§ãã â