Нужно ли проверять предикат std :: condition_variable перед ожиданием? - PullRequest
0 голосов
/ 22 апреля 2020

Из языка документации мне не ясно, нужно ли проверять предикат std :: condition_variable перед ожиданием.

На cppreference есть утверждение:

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 

На практике кажется, что проверять не нужно. Я просто беспокоюсь о неопределенном поведении, если не так.

Меня беспокоит ситуация, когда потребитель подключается к сети после производителя (то есть переменная условия была уведомлена одним потоком до того, как другой поток начнет его ждать):

#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;
}

В приведенном выше примере производитель запускается и уведомляет переменную условия. После этого потребитель запускается и уходит в режим ожидания на несколько секунд, прежде чем проверять переменную условия. Это практически гарантирует, что потребитель начнет ждать после того, как производитель уведомит переменную условия.

Несмотря на это, код на моем компьютере заканчивается и не зависает бесконечно. Фактически, из-за того, как быстро он заканчивается, я предполагаю, что это не из-за ложного пробуждения, но я не уверен, как бы я это проверил.

1 Ответ

2 голосов
/ 22 апреля 2020

Нет.

Если вы предоставляете предикат для wait, вам не нужно проверять его самостоятельно перед вызовом функции.

цитируемая статья cppreference.com , возможно, вводит в заблуждение (и / или неправильно) в этом отношении, хотя статья для wait на деньги в своем примере на основе кода, который идентичен определение, данное в стандарте :

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

Кажется, что второй набор пунктов на этой странице подходит к проблеме с точки зрения немного более высокого уровня, не принимая во внимание, что сам вызов wait() выполняет проверку pred() для вас, если вы ее предоставите.

Возможно, это связано с перегрузкой wait(), которую не принимает pred и в целом не требуется, чтобы переменная условия знала о состоянии, которое вы проверяете: вполне возможно использовать его для проверки некоторого "внешнего" условия. Но в настоящее время мы обычно просто вставляем лямбду в pred и покончим с этим, так что ...

Я столкнулся с этим несоответствием несколько недель go (предварительное обсуждение здесь ) но еще не придумали лучшую формулировку для статьи.

...