单个生产者/多个消费者死锁
Single producer / multiple consumer deadlock
以下代码在死锁中重新出现。问题是我无法弄清楚如何解锁等待条件变量的消费者。当满足某个条件时,使用者应该从堆栈循环和使用。我尝试在堆栈为空时退出,但当然它不起作用。
Stack.h
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();
};
堆栈.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) {}
主.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;
}
您的代码没有死锁,但您的线程正在等待更多输入,因为您尚未正确配置 done 的值。这里不可能调用 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。
同样正如马杜奇所回答的那样,您需要更改 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();
}
看起来你的 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()
相关文章:
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- 如何在没有死锁和/或争用的情况下正确使用 std::mutex C++?
- 用C++中的std::condition_variable将线程置于死锁中会有风险吗
- 使用 std::async 时死锁,将来作为成员
- 如何调试读写器锁的死锁?
- 为什么在Visual Studio 2013上的std::this_thread::sleep_for上死锁
- localtime() 函数正在调用 ___lll_lock_wait_private(),这会使线程陷入死锁
- 如何重现 Boost 进程文档提示的死锁?
- 多线程Windows GUI应用程序中的死锁
- 为什么printf会导致与future.get的死锁,而cout则不会?
- C++中具有阻塞队列和障碍的死锁
- 死锁使用 std::mutex 来保护多个线程中的 cout
- 避免并发等待对象中的死锁
- 在VC++中从DLLMAIN内部调用D3D的CREATEDEVICE时,它会创建一个死锁(loaderlock?)。有没有办法克服这个问题?最终目标内
- 当用2个螺纹锁定时,将recursive_mutex死锁
- 程序在 C++11 中使用条件变量进入死锁
- 一个线程提升的死锁
- 单个生产者/多个消费者死锁
- 当被调用方法使用调用方已锁定的同一锁时,如何避免死锁
- C 生产者消费者具有例外处理以防止死锁