C++ C++;生产者消费者陷入僵局
我正在尝试创建一个生产者-消费者程序,在这个程序中,消费者必须一直运行,直到所有生产者都完成,然后消费队列中剩余的内容(如果还有剩余内容),然后结束。你可以在下面查看我的代码,我想我知道问题在哪里(可能是死锁),但我不知道如何使它正常工作C++ C++;生产者消费者陷入僵局,c++,multithreading,producer-consumer,condition-variable,C++,Multithreading,Producer Consumer,Condition Variable,我正在尝试创建一个生产者-消费者程序,在这个程序中,消费者必须一直运行,直到所有生产者都完成,然后消费队列中剩余的内容(如果还有剩余内容),然后结束。你可以在下面查看我的代码,我想我知道问题在哪里(可能是死锁),但我不知道如何使它正常工作 #include<iostream> #include<cstdlib> #include <queue> #include <thread> #include <mutex>
#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;
}
#包括
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
阶级公司{
公众:
Company():producer_done(false){}
void start(int n_生产者,int n_消费者);//启动客户和生产者线程
void stop();//连接所有线程
无效消费者();
无效生产者();
/*一些其他的东西*/
私人:
条件变量cond;
互斥mut;
做得好;
排队产品;
向量发生器和U线程;
矢量线;
/*一些其他的东西*/
};
作废公司::消费者(){
而(!products.empty()){
唯一锁(mut);
while(products.empty()&&!producers\u done){
条件等待(锁定)当人们使用std::atomic
以及std::mutex
和std::condition_variable
时,几乎100%的情况下会导致死锁。这是因为对该原子变量的修改不受mutex的保护,因此在t之后更新该变量时,条件变量通知会丢失互斥锁已锁定,但在条件变量在使用者中等待之前
修复方法是在保持互斥锁时不使用std::atomic
,只修改和读取producers\u done
。例如:
void Company::consumer(){
for(;;){
unique_lock<mutex> lock(mut);
while(products.empty() && !producers_done)
cond.wait(lock);
if(products.empty())
break;
orders.pop();
}
}
当人们使用std::atomic
以及std::mutex
和std::condition_variable
时,几乎100%的情况下都会导致死锁。这是因为对该原子变量的修改不受mutex的保护,因此在mu之后更新该变量时,条件变量通知会丢失tex已锁定,但条件变量在使用者中等待之前
修复方法是在保持互斥锁时不使用std::atomic
,只修改和读取producers\u done
。例如:
void Company::consumer(){
for(;;){
unique_lock<mutex> lock(mut);
while(products.empty() && !producers_done)
cond.wait(lock);
if(products.empty())
break;
orders.pop();
}
}
通常,用一个好的抽象来隔离同步位是一个好主意。您在这里寻找的是一个有界缓冲区。现在您偷偷地集成了我的更改,它是否仍然死锁?您的代码将无法编译。发布a。我不想离主题太远,但一般来说,我们不想让算法吃掉所有system资源。我们应该考虑并设置一个合适的上限(如果合适的话,上限可以很大)。但我的主要观点是,有界缓冲区抽象隔离了所有锁定和等待。生产者所要做的就是制作项目并调用push()。消费者所要做的就是调用pop()并处理项目。(我还希望OP会查找有界缓冲区,看看它是什么。)我已经包括了最小的、完整的和可验证的示例。有一些简化,例如producer中的条件不同(应该由不同的类触发),但是死锁(或其他一些问题)仍然存在。通常用一个好的抽象来隔离同步位是一个好主意。您在这里寻找的是一个有界缓冲区。现在您偷偷地集成了我的更改,它是否仍然死锁?您的代码将无法编译。发布a。我不想离主题太远,但通常我们不想让算法吃东西启动所有系统资源。我们应该考虑并设置一个合适的上限(如果合适的话,上限可以很大)。但我的主要观点是,有界缓冲区抽象隔离了所有的锁定和等待。生产者所要做的就是创建项并调用push()。消费者所要做的就是调用pop()并处理项。(我还希望OP会查找有界缓冲区,看看它是什么。)我已经包括了最小的、完整的和可验证的示例。有一些简化,例如producer中的条件不同(应该由不同的类触发),但是死锁(或其他一些问题)仍然存在。我可能会把你和变量名混淆了-订单和产品应该是一回事-产品。我已经包括了你的建议,程序现在运行得更顺畅了-有时会以死锁结束,有时会结束,但消费者不消费产品。@adamlowlife Post a.Stack overflow不是一个很好的网站交互式调试。如果Maxim已经解决了您原来的问题,那么请接受答案,如果您还有其他问题,请稍后再回来。(另外,请将示例还原为其原始形式。)“当人们使用std::atomic以及std::mutex和std::condition_变量时,几乎100%的情况下会导致死锁。”似乎过于笼统。不一定总是这样。如果您检查修订历史并阅读原始代码,错误相当简单:条件变量condition中未检查终止标志。原子+互斥+条件变量==>死锁在我看来似乎是一个过度陈述。我可能把您与该变量混淆了名称-订单和产品应该是一件事-产品。我已经包括了您的建议,程序现在运行得更为正常-有时会以死锁结束,有时会结束,但消费者不会消费产品。@adamlowlife Post a.Stack overflow不是交互式调试的好网站。如果Maxim解决了您的问题ginal problem,然后请接受答案,如果您还有其他问题,请稍后再回来。(另外,请将示例还原为其原始形式。)“当人们使用std::atomic以及std::mutex和std::condition_变量时,几乎100%的情况下会导致死锁。”