Есть ли очередь notify_one ()? - PullRequest
0 голосов
/ 04 февраля 2019

Рассмотрим функцию первого потока и глобальные переменные:

    std::mutex mut;
    std::condition_variable officer;
    bool firstPlayerIsReady = false;
    bool secondPlayerIsReady = false;

void firstPlayer(){
    constexpr auto doIt = true;
    while(doIt)
    {
        std::unique_lock lock{mut};
        auto toContinue = ring();
        secondPlayerIsReady = true;
        firstPlayerIsReady = false;
        officer.notify_one();   //#1
        if(!toContinue) return;
        officer.wait(lock,[=](){ return firstPlayerIsReady;});
    }
}

Вызывает некоторое кольцо, и ring () возвращает условие продолжения;Затем он обновляет значения готовности для каждого потока в следующем цикле;

Рассмотрим следующий поток:

void secondPlayer(){
    constexpr auto doIt = true;
    while(doIt)
    {
        auto period = std::chrono::seconds(5);
        std::this_thread::sleep_for(period);

        std::unique_lock lock{mut};   //#2
        officer.wait(lock,[this](){ return secondPlayerIsReady;});
        auto toContinue = ring();
        firstPlayerIsReady = true;
        secondPlayerIsReady = false;
        officer.notify_one();
        if(!toContinue) return;
    }
}

Этот поток ожидает в течение 5 секунд и после этого блокируется с помощью wait () до первогопоток вызывает notify_one ();Далее, аналогично первому потоку.

Априори строка с тегом # 1 была выполнена раньше, чем строка с тегом # 2, поэтому уведомление было отправлено раньше, чем был заблокирован второй поток.Вопрос в том - есть ли очередь notify_one ()?В противном случае уведомление не было отправлено, очевидно.

1 Ответ

0 голосов
/ 04 февраля 2019

Нет очереди.Если один поток вызывает notify_one, а другие потоки не ждут, он ничего не сделает.

Вот почему у вас есть предикат, в вашем примере

officer.wait(lock,[this](){ return secondPlayerIsReady;});

Так что, когда поток вызываетэто, если secondPlayerIsReady истинно, тогда поток вообще не будет ждать, а просто пропустит эту строку.

Так что вызов слишком рано "1010 *" не является проблемой, пока флагустановить правильно.Просто помните, что флаг должен быть защищен мьютексом при изменении.

...