【发布时间】:2023-04-01 22:09:02
【问题描述】:
我正在尝试创建一个生产者-消费者程序,消费者必须继续运行,直到所有生产者完成,然后消费队列中剩余的内容(如果还有剩余),然后结束。您可以在下面查看我的代码,我想我知道问题出在哪里(可能是死锁),但我不知道如何使其正常工作。
#include<iostream>
#include<cstdlib>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std;
class Company{
public:
Company() : producers_done(false) {}
void start(int n_producers, int n_consumers); // start customer&producer threads
void stop(); // join all threads
void consumer();
void producer();
/* some other stuff */
private:
condition_variable cond;
mutex mut;
bool producers_done;
queue<int> products;
vector<thread> producers_threads;
vector<thread> consumers_threads;
/* some other stuff */
};
void Company::consumer(){
while(!products.empty()){
unique_lock<mutex> lock(mut);
while(products.empty() && !producers_done){
cond.wait(lock); // <- I think this is where the deadlock happens
}
if (products.empty()){
break;
}
products.pop();
cout << "Removed product " << products.size() << endl;
}
}
void Company::producer(){
while(true){
if((rand()%10) == 0){
break;
}
unique_lock<mutex> lock(mut);
products.push(1);
cout << "Added product " << products.size() << endl;
cond.notify_one();
}
}
void Company::stop(){
for(auto &producer_thread : producers_threads){
producer_thread.join();
}
unique_lock<mutex> lock(mut);
producers_done = true;
cout << "producers done" << endl;
cond.notify_all();
for(auto &consumer_thread : consumers_threads){
consumer_thread.join();
}
cout << "consumers done" << endl;
}
void Company::start(int n_producers, int n_consumers){
for(int i = 0; i<n_producers; ++i){
producers_threads.push_back(thread(&Company::producer, this));
}
for(int i = 0; i<n_consumers; ++i){
consumers_threads.push_back(thread(&Company::consumer, this));
}
}
int main(){
Company c;
c.start(2, 2);
c.stop();
return true;
}
我知道,这里有很多与生产者-消费者相关的问题,我已经浏览了至少 10 个,但没有一个回答我的问题。
【问题讨论】:
-
用良好的抽象来隔离同步位通常是个好主意。您在这里寻找的是有界缓冲区。
-
现在你偷偷地整合了我的更改,它仍然死锁吗?
-
您的代码无法编译。发布Minimal, Complete, and Verifiable example。
-
我不想离题太远,但总的来说我们不想让算法吃掉所有的系统资源。我们应该考虑并设置一个合适的上限(如果合适,可以相当大)。但我的主要观点是有界缓冲区抽象隔离了所有锁定和等待。生产者所要做的就是制作物品并调用 push()。消费者所要做的就是调用 pop() 并处理这些项目。 (我还希望 OP 会查找有界缓冲区以查看它是什么。)
-
我已经包含了最小、完整和可验证的示例。有一些简化,例如生产者中的条件不同(它应该由不同的类触发),但死锁(或其他一些问题)仍然存在。
标签: c++ multithreading producer-consumer condition-variable