生产者-消费者实现中的条件变量应如何初始化 [英] How should conditional variables in producer-consumer implementations be initialized

查看:46
本文介绍了生产者-消费者实现中的条件变量应如何初始化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图理解使用条件变量来实现生产者-消费者缓冲区.我有以下代码,该代码实现了整数队列(可能是linux文件描述符).该代码按预期工作,但我试图理解原因.入队和出队操作都在通知另一个条件变量之前先等待某个条件变量.这些等待为何畅通无阻?这是由于虚假唤醒引起的吗?

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();
}

推荐答案

add在_notFullCv上等待,并删除在_notEmptyCv上等待.这些怎么办条件变量是第一次发出信号的?

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

他们没有.如果您查看文档,则 std的重载接受锁 l 和谓词 pred 的:: condition_variable :: wait 有效地实现为...

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);

您情况下的重要部分是在等待之前 检查条件.因此,第一次调用 add 会发现队列未满,并且不会调用 std :: condition_variable :: wait (不带谓词).

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.

这篇关于生产者-消费者实现中的条件变量应如何初始化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆