Skip to content

NotificationQueue::wakeUpAll() lost-wakeup race causes deadlock on shutdown #5213

@aleks-f

Description

@aleks-f

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:

  1. set a termination flag for every worker thread
  2. call the wakeUpAll() method
  3. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions