'notify_one only when there are waiting threads is correct?

I've seen the following type of a dispatch queue implementation several times where the thread pushing a new element to the queue calls notify_one only when the queue was empty before pushing the element. This condition would reduce unnecessary notify_one calls because q.size() != 0 before pushing a new element means there are only active threads (assuming there are multiple consumer threads).

#include <queue>
#include <condition_variable>
#include <mutex>

using Item = int;
std::queue<Item> q;
std::condition_variable cv;
std::mutex m;

void process(Item i){}

void pop() {
  while (true) {
    std::unique_lock<std::mutex> lock(m);
    // This thread releases the lock and start waiting.
    // When notified, the thread start trying to re-acquire the lock and exit wait().
    // During the attempt (and thus before `pop()`), can another `push()` call acquire the lock? 
    cv.wait(lock, [&]{return !q.empty();});
    auto item = q.front();
    q.pop();
    process(item);
  }
}

void push(Item i) {
  std::lock_guard<std::mutex> lock(m);
  q.push(i);
  if (q.size() == 1) cv.notify_one();
}

int main() { /* ... */ }

However, is the following scenario possible ? Suppose that all the consumer threads are waiting.

  1. the pushing thread acquires the lock and push a new element and calls notify_one because the queue was empty.
  2. a notified thread tries to re-acquire the lock (and exit wait())
  3. the pushing thread acquires the lock again and pushes another element before a notified thread re-acquires the lock.

In this case, no notify_one call wouldn't occur after 3. and there would be only one active thread when the queue isn't empty.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source