C ++生产者消费者陷入僵局

问题描述 投票:0回答:1

我正在尝试创建一个生产者 - 消费者计划,消费者必须继续运行直到所有生产者都完成,然后消耗队列中剩下的东西(如果还剩下什么)然后结束。您可以检查我的代码,我想我知道问题(可能是死锁)的位置,但我不知道如何让它正常工作。

  #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个问题,但没有人回答我的问题。

c++ multithreading producer-consumer condition-variable
1个回答
2
投票

当人们使用std::atomic以及std::mutexstd::condition_variable时,几乎100%的情况都会导致死锁。这是因为对该原子变量的修改不受互斥锁的保护,因此在互斥锁被锁定之后但在消费者中条件变量等待之前更新该变量时,条件变量通知会丢失。

修复将是不使用std::atomic并且仅在保持互斥锁时修改和读取producers_done。例如。:

void Company::consumer(){
    for(;;){
        unique_lock<mutex> lock(mut);
        while(products.empty() && !producers_done)
            cond.wait(lock);
        if(products.empty())
            break;
        orders.pop();
    }   
}

代码中的另一个错误是在while(!products.empty())中它调用products.empty()而不持有互斥锁,从而导致竞争条件。


下一个错误是在等待使用者线程终止时保持互斥锁被锁定。固定:

{
    unique_lock<mutex> lock(mut);
    producers_done = true;
    // mutex gets unlocked here.
}
cond.notify_all();

for(auto &consumer_thread : consumers_threads)
    consumer_thread.join();
© www.soinside.com 2019 - 2024. All rights reserved.