@@ -33,8 +33,12 @@ class LoopQueueGuard {
33
33
34
34
public:
35
35
explicit LoopQueueGuard (MessageQueue* queue) : queue_(queue) {
36
- queue_->workerCount_ ++;
37
36
getRunningQueue ()[queue]++;
37
+
38
+ {
39
+ std::unique_lock<std::mutex> lk (queue_->queueMutex_ );
40
+ ++queue_->workerCount_ ;
41
+ }
38
42
}
39
43
40
44
SCRIPTX_DISALLOW_COPY_AND_MOVE (LoopQueueGuard);
@@ -45,7 +49,17 @@ class LoopQueueGuard {
45
49
q.erase (queue_);
46
50
}
47
51
48
- queue_->workerCount_ --;
52
+ // bugfix: awaitTermination won't return even if all worker quit.
53
+ // https://en.cppreference.com/w/cpp/thread/condition_variable
54
+ // follow what the STD told us to
55
+ // "Even if the shared variable is atomic, it must be modified while owning the mutex to
56
+ // correctly publish the modification to the waiting thread."
57
+ // DEEP EXPLAINATION:
58
+ // https://stackoverflow.com/questions/38147825/shared-atomic-variable-is-not-properly-published-if-it-is-not-modified-under-mut
59
+ {
60
+ std::unique_lock<std::mutex> lk (queue_->queueMutex_ );
61
+ --queue_->workerCount_ ;
62
+ }
49
63
queue_->workerQuitCondition_ .notify_all ();
50
64
}
51
65
@@ -180,7 +194,7 @@ void MessageQueue::awaitTermination() {
180
194
workerQuitCondition_.wait (lk, [this ] { return workerCount_ == 0 ; });
181
195
}
182
196
183
- bool MessageQueue::isShutdown () {
197
+ bool MessageQueue::isShutdown () const {
184
198
std::unique_lock<std::mutex> lk (queueMutex_);
185
199
return shutdown_ != ShutdownType::kNone ;
186
200
}
@@ -386,7 +400,7 @@ MessageQueue::LoopReturnType MessageQueue::loopQueue(MessageQueue::LoopType loop
386
400
if (loopType == LoopType::kLoopOnce ) {
387
401
onceMessageCount = dueMessageCount ();
388
402
}
389
- MessageQueue:: LoopReturnType returnType = LoopReturnType::kRunOnce ;
403
+ LoopReturnType returnType = LoopReturnType::kRunOnce ;
390
404
391
405
while (true ) {
392
406
Message* message = awaitDueMessage (loopType, onceMessageCount, returnType);
0 commit comments