-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Closed
Copy link
Labels
Milestone
Description
Bug
NotificationQueue::wakeUpAll() only signals threads that are already blocked in waitDequeueNotification(). If a consumer thread has not yet entered the wait when wakeUpAll() is called, the signal is lost and the thread blocks indefinitely on the next waitDequeueNotification() call. This causes a deadlock during shutdown when the pattern recommended in the class documentation is followed:
- set a termination flag for every worker thread
- call the wakeUpAll() method
- join each worker thread
Root cause
wakeUpAll() iterates _waitQueue and signals each WaitInfo::nfAvailable event, then clears the queue. If a thread calls waitDequeueNotification() after wakeUpAll() returns, it creates a new WaitInfo, adds itself to the (now empty) _waitQueue, and blocks on nfAvailable.wait() with no one to wake it:
Thread A (shutdown) Thread B (worker)
───────────────────── ─────────────────────
while (!_stopped) { // _stopped is false
_stopped = true;
wakeUpAll():
lock(_mutex)
_waitQueue is empty → no-op
unlock(_mutex)
waitDequeueNotification():
lock(_mutex)
queue empty, create WaitInfo
push to _waitQueue
unlock(_mutex)
nfAvailable.wait() // blocks forever
_mainThread.join() // deadlock
Reactions are currently unavailable