You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++单生产者多消费者模型阻塞问题求助

问题分析与解决方案

你的问题核心在于消费者线程无法感知生产者已完成生产:当剩余元素数量等于消费者线程数时,部分线程消费完元素后,剩下的线程会因storage暂时为空且没有新的通知而永久阻塞。此外,main函数中storageCV.notify_all()放在join之后,根本无法执行到——此时消费者已经卡住,主线程会一直等待消费者线程结束。

修复步骤

  1. 添加生产者完成标志:新增全局布尔变量producer_done,标记生产者是否完成所有元素生产。
  2. 修改消费者等待条件:将等待条件改为!storage.empty() || producer_done,确保生产者完成后,消费者能被唤醒并检查剩余元素。
  3. 调整消费者退出逻辑:唤醒后先判断producer_done且storage.empty时才退出,否则继续消费剩余元素。
  4. 修正主线程通知时机:生产者结束后立即设置producer_done并调用notify_all(),唤醒所有等待的消费者。

修复后的完整代码

#include <chrono>
#include <condition_variable>
#include <functional>
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>

#define CONSUMER_COUNT 4
#define STORAGE_SIZE CONSUMER_COUNT * 10000

class Foo {
private:
  int _id;

public:
  Foo(int id) : _id(id) {}
  int getId() const { return _id; }
};

std::vector<Foo> storage;
std::mutex storageMutex;
std::condition_variable storageCV;
bool producer_done = false; // 新增生产者完成标志

void Producer(int limit) {
  for (int i = 0; i < limit; ++i) {
    std::lock_guard<std::mutex> lg{storageMutex};
    storage.emplace_back(Foo(i));
    storageCV.notify_one();
  }
  // 生产完成后设置标志并通知所有消费者
  std::lock_guard<std::mutex> lg{storageMutex};
  producer_done = true;
  storageCV.notify_all();
}

void Consumer(int id) {
  while (true) {
    std::unique_lock<std::mutex> ul{storageMutex};
    // 等待条件:有元素可消费 或者 生产者已完成
    storageCV.wait(ul, []() { return !storage.empty() || producer_done; });
    
    // 生产者完成且无剩余元素时退出
    if (producer_done && storage.empty()) {
      return;
    }
    
    // 有元素则消费
    if (!storage.empty()) {
      storage.pop_back();
    }
  }
}

int main(int argc, char *argv[]) {
  std::vector<std::thread> consumers;
  consumers.reserve(CONSUMER_COUNT);

  auto producer = std::thread(Producer, STORAGE_SIZE);

  for (int i = 0; i < CONSUMER_COUNT; ++i) {
    consumers.emplace_back(std::thread(Consumer, i));
  }

  producer.join();
  for (auto &consumer : consumers) {
    consumer.join();
  }

  std::cout << "[MAIN] Done!" << std::endl;
  std::cout << "Storage is left with " << storage.size() << " items!" << std::endl;

  return 0;
}

关键说明

  • 线程安全的标志设置:设置producer_done时必须持有互斥锁,确保消费者线程能看到最新值,避免内存可见性问题。
  • 等待条件的完整性:wait的谓词必须包含producer_done,否则生产者完成后,消费者可能永远阻塞在wait调用上。
  • 退出逻辑的合理性:先检查生产者状态和存储状态,避免提前退出导致剩余元素未被消费。

内容的提问来源于stack exchange,提问作者Zlatan Radovanovic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 15:35:32