Условная переменная C ++ без времени ожидания - PullRequest
2 голосов
/ 18 февраля 2020

Недавно я столкнулся с проблемой, которая связана с условной переменной в C ++. Код показан ниже:

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

std::condition_variable cv;
std::mutex mutex;

int main(){

std::unique_lock<std::mutex> uniqueLock(mutex);

while (true)
{

    if(cv.wait_for(uniqueLock, std::chrono::milliseconds(1000)) == std::cv_status::no_timeout)
    {
      std::cout << "has image" << std::endl;

    }
    else
    {
        std::cout<< "time out " << std::endl;
    }

}

return 0;
}

Цель этого кода заключается в следующем: каждый раз, когда переменная условия уведомляется в другом потоке (cv.notify ()), в консоли отображается «имеет изображение» и если он не может быть уведомлен более 1000 миллисекунд, он показывает «время ожидания».

Таким образом, теоретический вывод приведенного выше кода (потому что переменная условия не уведомляется):

time out
time out
time out
time out

Но когда я выполняю этот код в Vs2015, я обнаружил, что вывод странный:

has image
time out
has image
time out
time out
time out
has image
has image
time out
time out
time out
time out
time out
has image
has image

Я хотел бы знать, почему у меня есть этот вывод и как я могу достичь своей цели

Спасибо!

1 Ответ

1 голос
/ 18 февраля 2020

Я не знаю, в чем причина вашей ошибки (но в комментариях есть некоторые правдоподобные объяснения). Тем не менее, один из способов решить вашу проблему - использовать другую перегрузку wait_for, которая включает в себя предикат.

Это может выглядеть примерно так (hasImage здесь просто бул, замените его чем-нибудь это имеет смысл для ваших нужд - !imageStorage.empty() или аналогичный):

while (true)
{

    if (cv.wait_for(uniqueLock, std::chrono::milliseconds(1000), []() {return hasImage;}))
    {
        std::cout << "has image" << std::endl;
        hasImage = false;
    }
    else
    {
        std::cout << "time out " << std::endl;
    }

}

Уместным моментом является то, что предикат проверяет, действительно ли существует новое изображение, а если его нет, то он должен продолжать wait.

Одним из ограничений этого метода является то, что, если предикат возвращает false (без изображения), то вы не знаете, проснулась ли переменная условия из-за ложного пробуждения, тайм-аута или, если они действительно существуют. было изображение, но другой поток просто забрал его, прежде чем этот проснулся. Но если с этим может справиться ваш дизайн, то этот вариант работает очень хорошо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...