Как следует инициализировать условные переменные в реализациях производитель-потребитель - PullRequest
0 голосов
/ 13 февраля 2019

Я пытаюсь понять использование условных переменных для реализации буферов производитель-потребитель.У меня есть следующий код, который реализует очередь для целых чисел (которые могут быть дескрипторами файлов Linux).Код работает, как и ожидалось, но я пытаюсь понять, почему.Операции enqueue и dequeue ожидают какую-то условную переменную, а затем сигнализируют другую условную переменную.Почему эти ожидания разблокировки?Это из-за ложных пробуждений?

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

using namespace std::chrono_literals;
using std::cout;
using std::endl;

class FDQueue
{
    std::mutex _mutex;
    std::condition_variable _notEmptyCv, _notFullCv;
    std::list<int> _fds;
    size_t _maxSize;

public:
    void add(int fd) {
        std::unique_lock<std::mutex> locker(this->_mutex);
        this->_notFullCv.wait(locker, [this](){return this->_fds.size() < this->_maxSize;});
        cout<<"Enqueue "<<endl;
        this->_fds.push_back(fd);
        locker.unlock();
        this->_notEmptyCv.notify_one();
    }

    int remove() {
        std::unique_lock<std::mutex> locker(_mutex);
        this->_notEmptyCv.wait(locker, [this](){return this->_fds.size() > 0;});
        int fd = this->_fds.front();
        this->_fds.pop_front();
        cout<<"Dequeue"<<endl;
        locker.unlock();
        this->_notFullCv.notify_all();
        return fd;
    }

    FDQueue(size_t maxSize) : _maxSize(maxSize) {}
};

FDQueue queue(5);

void producer() {
    while (true) {
        queue.add(0);
        std::this_thread::sleep_for(2s);
    }
}
void consumer() {
    while (true) {
        queue.remove();
    }
}

int main() {
    std::thread t1(producer);
    std::thread t2(consumer);
    t1.join();
    t2.join();
}

1 Ответ

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

добавить ожидания на _notFullCv и удалить ожидания на _notEmptyCv.Как эти условные переменные получают сигнал в первый раз?

Нет.Если вы посмотрите на документацию , перегрузка std::condition_variable::wait, которая принимает блокировку l и предикат pred, эффективно реализуется как ...

while (!pred())
  wait(l);

Важная частьв вашем случае, что условие проверяется до ожидания.Следовательно, первый вызов add обнаружит, что очередь не заполнена, и вызов std::condition_variable::wait (без предиката) не будет выполнен.

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