c++ - C++生产者使用者陷入僵局

标签 c++ multithreading producer-consumer condition-variable

我正在尝试创建一个生产者-消费者程序,在该程序中,消费者必须继续运行,直到所有生产者都完成为止,然后消费队列中剩余的内容(如果还有剩余),然后结束。您可以在下面检查我的代码,我想我知道问题出在哪里(可能是死锁),但是我不知道如何使其正常工作。

  #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个问题,但没有一个提供我问题的答案。

最佳答案

当人们同时使用std::atomicstd::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();

关于c++ - C++生产者使用者陷入僵局,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60037047/

相关文章:

c++ - 编码和等待多个相互依赖的线程的算法、模式或最佳实践?

java - 同时执行 2 个任务列表

java - 生产者和消费者共享队列,其值来自 HttpRequest

c++ - 如何传递带有泛型参数作为参数的 lambda 函数?

c++ - LNK1104 无法打开文件 '...lib.obj'

c - Win Api-SetEvent和WaitForSingleObject,线程之间的内存同步

c++ - 使用 waitpid 等待另一个进程的线程

C#生产者/消费者

c++ - 创建一个 Makefile 来构建 swigged 模块

c++ - 我可以在类定义的头文件中声明一个字符串吗?