How should conditional variables in producer-consumer implementations be initialized

陌路散爱 提交于 2021-01-28 09:51:12

问题


I am trying to understand the use of conditional variables to implement producer-consumer buffers. I have the following code, which implements a queue for integers (which could be linux file descriptors). The code works as expected, but I am trying to understand why. Both enqueue and dequeue operations wait on some conditional variable before signaling the other conditional variable. Why are these waits unblocking? Is this due to spurious wakeups?

#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:


add waits on _notFullCv, and remove waits on _notEmptyCv. How do these conditional variables get signaled for the very first time?

They don't. If you look at the documentation, the overload of std::condition_variable::wait that accepts a lock l and predicate pred is effectively implemented as...

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

The important part in your case being that the condition is checked before waiting. Hence, the first call to add will find the queue not full and no call to std::condition_variable::wait (without a predicate) will be made.



来源:https://stackoverflow.com/questions/54672365/how-should-conditional-variables-in-producer-consumer-implementations-be-initial

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!