【问题标题】:How should conditional variables in producer-consumer implementations be initialized生产者-消费者实现中的条件变量应该如何初始化
【发布时间】:2019-02-13 14:18:37
【问题描述】:

我试图了解使用条件变量来实现生产者-消费者缓冲区。我有以下代码,它实现了一个整数队列(可能是 linux 文件描述符)。该代码按预期工作,但我试图理解为什么。入队和出队操作都等待某个条件变量,然后再向另一个条件变量发出信号。为什么这些等待会解除阻塞?这是由于虚假唤醒造成的吗?

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

【问题讨论】:

  • 为什么不使用boost lock-freelibcdc 的无锁队列。 2.“等待解锁”-为什么你认为这段代码是“解锁”,删除你的黑客std::this_thread::sleep_for(2s);并检查没有它的代码。
  • 为什么add 在等待?它应该只是produce
  • 我知道可能有其他选择。我想要做的是理解为什么这是有效的。代码运行良好,无需在生产者中进行 2 秒睡眠。 add等待的原因是为了防止队列溢出(队列限制为5个条目)。
  • 您声明"What I am trying to do is understand why this is working"。您能否准确说明为什么您认为它不应该起作用。抱歉,如果我遗漏了什么。

标签: c++ multithreading c++11


【解决方案1】:

在 _notFullCv 上添加等待,在 _notEmptyCv 上删除等待。这些怎么做 条件变量第一次得到信号?

他们没有。如果您查看documentation,接受锁l 和谓词predstd::condition_variable::wait 的重载被有效地实现为...

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

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

【讨论】:

    猜你喜欢
    • 2017-12-05
    • 1970-01-01
    • 2018-08-26
    • 1970-01-01
    • 1970-01-01
    • 2015-02-07
    • 1970-01-01
    • 1970-01-01
    • 2011-01-23
    相关资源
    最近更新 更多