Home > Enterprise >  Why does std::condition_variable wait() require a std::unique_lock arg?
Why does std::condition_variable wait() require a std::unique_lock arg?

Time:03-04

My thread does not need to be locked. std::unique_lock locks thread on construction. I am simply using cond_var.wait() as a way to avoid busy waiting. I have essentially circumvented the auto-locking by putting the unique_lock within a tiny scope and hence destroying the unique lock after it leaves the tiny scope. Additionally, there is only a single consumer thread if that's relevant.

{
std::unique_lock<std::mutex> dispatch_ul(dispatch_mtx);
pq_cond.wait(dispatch_ul);
}

Is there possibly a better option to avoid the unnecessary auto-lock functionality from the unique_lock? I'm looking for a mutexless option to simply signal the thread, I am aware of std::condition_variable_any but that requires a mutex of sorts which is yet again unnessesary in my case.

CodePudding user response:

You need a lock to prevent this common newbie mistake:

  1. Producer thread produces something,
  2. Producer thread calls some_condition.notify_all(),
  3. Producer thread goes idle for a while,

meanwhile:

  1. Consumer thread calls some_condition.wait(...)
  2. Consumer thread waits,...
  3. And waits,...
  4. And waits.

A condition variable is not a flag. It does not remember that it was notified. If the producer calls notify_one() or notify_all() before the consumer has entered the wait() call, then the notification is "lost."

In order to prevent lost notifications, there must be some shared data that tells the consumer whether or not it needs to wait, and there must be a lock to protect the shared data.

The producer should:

  1. Lock the lock,
  2. update the shared data,
  3. notify the condition variable,
  4. release the lock

The consumer must then:

  1. Lock the lock,
  2. Check the shared data to see if it needs wait,
  3. Wait if needed,
  4. consume whatever,
  5. release the lock.

The consumer needs to pass the lock in to the wait(...) call so that wait(...) can temporarily unlock it, and then re-lock it before returning. If wait(...) did not unlock the lock, then the producer would never be able to reach the notify() call.

  • Related