0
votes

It is not clear to me from the documentation language whether one must check the predicate of a std::condition_variable before waiting.

On cppreference, there is the statement:

Any thread that intends to wait on std::condition_variable has to
    1. ...
    2. check the condition, in case it was already updated and notified 

In practice, it seems that one does not need to check. I am simply worried about undefined behavior if one does not.

The situation that I am concerned about is the one where a consumer comes online after a producer (that is, the condition variable has been notified by one thread before the other thread starts waiting for it):

#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>

int main() {
  std::condition_variable condition_var;
  std::mutex mutex;
  std::vector<std::thread> threads;
  bool flag = false;

  // Producer
  threads.emplace_back([&]() {
    {
      std::lock_guard<std::mutex> lock(mutex);
      flag = true;
      printf("%s\n", "flag = true");
    }
    condition_var.notify_all();
  });

  // Consumer
  threads.emplace_back([&]() {
    std::this_thread::sleep_for(std::chrono::seconds(3));
    {
      std::unique_lock<std::mutex> lock(mutex);
      condition_var.wait(lock, [&]() { return flag; });
      printf("%s\n", "Consumer finished");
    }
  });

  for (auto& thread : threads) {
    if (thread.joinable()) {
      thread.join();
    }
  }
  return 0;
}

In the above example, a producer starts up and notifies a condition variable. The consumer starts after that, and is put to sleep for a few seconds before checking the condition variable. This practically ensures that the consumer starts waiting after the producer has notified the condition variable.

Despite this, the code finishes on my computer and does not hang indefinitely. In fact, due to how quickly it finishes, I presume that this is not due to spurious wakeup, but I am not sure how I would check that.

1
You don't need to check if you use overload with predicate. See en.cppreference.com/w/cpp/thread/condition_variable/wait - Equivalent to while (!pred()) { wait(lock); } - dewaffled
@dewaffled y u answer in comments - Asteroids With Wings

1 Answers

2
votes

No.

If you supply a predicate to wait, you do not need to check it yourself before calling the function.

The cited cppreference.com article is arguably misleading (and/or wrong) in this regard, though the article for wait is on the money in its code-based example, which is identical to the definition given in the standard:

while (!pred())
   wait(lock);

It seems the second set of bullet points on that page are coming at the problem from a slightly higher-level perspective, not taking into account that the wait() call itself does perform a check pred() for you if you supply one.

This is probably because there is an overload of wait() that doesn't take a pred, and in general there is no requirement that the condition variable know about the condition you're testing for: it's quite possible to use it to check some "external" condition. But, nowadays, we usually just shove a lambda into pred and be done with it, so…

I encountered this inconsistency a few weeks ago (prior discussion here) but have yet to come up with better wording for the article.