繁体   English   中英

单生产者/多消费者僵局

[英]Single producer / multiple consumer deadlock

以下代码导致死锁。 问题是我无法弄清楚如何释放等待条件变量的消费者。 满足特定条件时,使用者应从堆栈中循环并进行消耗。 我试过在堆栈为空时退出,但是当然不起作用。

堆栈

class Stack {
private:
    std::stack<int> stack;
    std::mutex mutex;
    std::condition_variable is_empty;
    bool done;

public:
    Stack();

    void push(int);
    void pop();
    void print();

    bool isDone() const;

    ~Stack();
};

Stack.cpp

#include <iostream>
#include <sstream>
#include <thread>
#include "Stack.h"

void Stack::push(int x) {
    std::lock_guard lock(mutex);
    std::stringstream msg1;
    msg1 << "producer " << std::this_thread::get_id() << " pushing " << x << std::endl;
    std::cout << msg1.str();
    stack.push(x);
    std::stringstream msg;
    msg << "producer " << std::this_thread::get_id() << ": " << x << " pushed" << std::endl;
    std::cout << msg.str();
    is_empty.notify_all();
}

void Stack::pop() {
    std::unique_lock lock(mutex);
    std::stringstream msg;
    msg << "consumer " << std::this_thread::get_id() << " waiting to consume" << std::endl;
    std::cout << msg.str();
    is_empty.wait(lock, [this] { return !stack.empty(); });
    if (!stack.empty()) {
        stack.pop();
        std::stringstream msg1;
        msg1 << "consumer " << std::this_thread::get_id() << " popped" << std::endl;
        std::cout << msg1.str();
    } else {
        done = true;
        is_empty.notify_all();
    }
}

void Stack::print() {
    std::lock_guard lock(mutex);
    for (int i = 0; i < stack.size(); i++) {
        std::cout << "\t" << stack.top() << std::endl;
    }
}

Stack::~Stack() {

}

bool Stack::isDone() const {
    return done;
}

Stack::Stack() : done(false) {}

main.cpp

#include <thread>
#include <vector>
#include <iostream>
#include "Stack.h"

int main() {

    Stack stack;
    std::vector<std::thread> producer;
    std::vector<std::thread> consumer;

    for (int i = 0; i < 10; i++) {
        consumer.emplace_back([&stack]{
            while (!stack.isDone()) {
                stack.pop();
            }
        });
    }

    for (int i = 0; i < 1; i++) {
        producer.emplace_back([&stack]{
            for (int j = 0; j < 5; ++j) {
                stack.push(random());
            }
        });
    }

    for (int k = 0; k < producer.size(); k++) {
        producer[k].join();
        std::cout << producer[k].get_id() << " joined" << std::endl;
        stack.print();
    }

    for (int j = 0; j < consumer.size(); j++) {
        consumer[j].join();
        std::cout << consumer[j].get_id() << " joined" << std::endl;
        stack.print();
    }


    return 0;
}

看起来您的pop函数中有一个逻辑错误:万一从堆栈中弹出一个元素,就永远不要调用notify_all()。

正确的方式应该是这样的:

void Stack::pop() {
   std::unique_lock lock(mutex);
   std::stringstream msg;
   msg << "consumer " << std::this_thread::get_id() << " waiting to consume" << std::endl;
   std::cout << msg.str();
   is_empty.wait(lock, [this] { return !stack.empty(); });
   if (!stack.empty()) {
     stack.pop();
     std::stringstream msg1;
     msg1 << "consumer " << std::this_thread::get_id() << " popped" << std::endl;
     std::cout << msg1.str();
   } else {
       done = true;
   }
   is_empty.notify_all();
}

您还可以在主目录中的push()之前调用pop()

您的代码没有死锁,但您的线程正在等待更多输入,因为您没有正确配置完成的值。 不可能在这里调用else条件

is_empty.wait(lock, [this] { return !stack.empty(); });
    if (!stack.empty()) {
        stack.pop();
        std::stringstream msg1;
        msg1 << "consumer " << std::this_thread::get_id() << " popped" << std::endl;
        std::cout << msg1.str();
    } else {
        done = true;
        is_empty.notify_all();
    }

从代码看,您想要的是生产者停止生产之后,消费者应该醒来并清空。 但这不是实现它的方法。 生产者推送了5个元素后,应从此处设置done = true。

另外,正如madducci回答的那样,您需要更改notify_all()的位置;

这对我有用

is_empty.wait(lock, [&] { return stack.size()>0 || done; });
    if (!stack.empty()) {
        int val=stack.top();
        stack.pop();
        std::stringstream msg1;
        msg1 << "consumer " << std::this_thread::get_id() << " popped " <<val<<std::endl;
        std::cout << msg1.str();
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM