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

C++14并发编程问题:消费者线程需等生产者完成才同步

解决Condition Variable导致消费者等待生产者全部完成才同步的问题

嘿,我懂你碰到的这个问题——刚用condition_variable写生产者消费者模型时,很容易踩这个坑:本来想做到生产一个就消费一个,结果变成了生产者把所有数据都塞完,消费者才开始干活,对吧?

问题根源分析

你的代码大概率是这两个原因导致的:

  • 生产者只在所有元素都添加完后才调用一次notify_one()/notify_all(),而不是每生产一个就通知一次;
  • 消费者的等待逻辑只检查了done标志,没同时检查共享容器里有没有新元素,导致它一直阻塞到生产者标记完成才被唤醒。

修正后的完整代码

下面是调整后的生产者/消费者示例,能实现生产一个就消费一个的同步逻辑:

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

std::atomic<bool> done{false};
std::mutex data_mutex; // 用来保护共享vector的互斥量
std::condition_variable data_ready;
std::vector<int> shared_data;

// 生产者线程:逐个生产数字并通知消费者
void producer() {
    for (int i = 0; i < 10; ++i) {
        {
            // 锁范围内操作共享容器,保证线程安全
            std::lock_guard<std::mutex> lock(data_mutex);
            shared_data.push_back(i);
        }
        // 解锁后立即通知消费者有新数据
        data_ready.notify_one();
        // 模拟生产耗时,方便看同步效果
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
    // 标记生产完成,最后再通知一次避免消费者阻塞
    done = true;
    data_ready.notify_one();
}

// 消费者线程:等待新数据并及时处理
void consumer() {
    while (true) {
        std::unique_lock<std::mutex> lock(data_mutex);
        // 用带谓词的wait避免虚假唤醒,等待条件是「有新数据」或「生产者已完成」
        data_ready.wait(lock, []{ 
            return !shared_data.empty() || done.load(); 
        });

        // 一次性处理所有可用数据(避免多次唤醒)
        while (!shared_data.empty()) {
            std::cout << "消费了数字: " << shared_data.front() << std::endl;
            shared_data.erase(shared_data.begin());
        }

        // 生产者完成且没有剩余数据时,退出线程
        if (done.load() && shared_data.empty()) {
            break;
        }
    }
    std::cout << "消费者线程已退出" << std::endl;
}

int main() {
    std::thread prod_thread(producer);
    std::thread cons_thread(consumer);

    prod_thread.join();
    cons_thread.join();

    return 0;
}

关键调整点说明

  • 保护共享数据:shared_data必须被data_mutex包裹,因为vector的读写操作不是线程安全的,任何对它的操作都要在锁的范围内进行;
  • 及时通知:生产者每添加一个元素就调用notify_one(),这样消费者能立刻被唤醒处理新数据,而不是等全部生产完毕;
  • 正确的等待条件:使用wait()的重载版本,传入lambda谓词,既可以避免虚假唤醒,又明确了消费者需要等待的触发条件;
  • 收尾通知:生产者完成后必须再调用一次notify_one(),否则消费者可能会一直阻塞在wait()上——因为此时done已经为true,但它没机会检查这个条件。

这样调整后,你就能看到消费者跟着生产者的节奏,生产一个就消费一个啦~

内容的提问来源于stack exchange,提问作者Andres Barrio

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 06:23:40