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

C++11 condition_variable虚假唤醒异常:生产者消费者代码排查

解决C++11 condition_variable虚假唤醒问题的生产者/消费者实现

看起来你在写生产者消费者模型时踩了condition_variable虚假唤醒的坑——这个问题在C++11里很常见,核心原因是wait()可能在没有收到通知的情况下被系统唤醒,如果只用if判断条件就会直接继续执行,导致逻辑错误。我来帮你修正代码,同时解释关键的注意点:

首先,先看修正后的完整代码:

#include <iostream>
#include <thread>
#include <condition_variable>
#include <mutex>
#include <chrono>
#include <queue>
using namespace std;

condition_variable cond_var;
mutex m;

int main() {
    int c = 0;
    bool done = false;
    cout << boolalpha;
    queue<int> goods;

    // 生产者线程
    thread producer([&](){
        for (int i = 0; i < 10; ++i) {
            // 用unique_lock自动管理锁,比手动lock/unlock更安全
            unique_lock<mutex> lock(m);
            goods.push(i);
            c++;
            cout << "生产者生产了: " << i << ",当前队列大小: " << goods.size() << endl;
            // 通知一个消费者
            cond_var.notify_one();
            // 这里lock会在作用域结束时自动解锁
        }
        // 生产完成后设置done标志,并通知所有消费者
        unique_lock<mutex> lock(m);
        done = true;
        cond_var.notify_all();
    });

    // 消费者线程
    thread consumer([&](){
        while (true) {
            unique_lock<mutex> lock(m);
            // 用while循环检查条件,解决虚假唤醒!
            // 每次wait返回后都重新确认:队列不为空 或者 生产已完成
            cond_var.wait(lock, [&](){ return !goods.empty() || done; });
            
            // 如果生产完成且队列为空,退出循环
            if (done && goods.empty()) {
                break;
            }

            // 消费数据
            int item = goods.front();
            goods.pop();
            c--;
            cout << "消费者消费了: " << item << ",当前队列大小: " << goods.size() << endl;
        }
        cout << "消费者退出" << endl;
    });

    producer.join();
    consumer.join();
    cout << "最终c的值: " << c << endl;
    return 0;
}

接下来解释几个关键的修复点:

  • 用std::unique_lock替代手动锁管理:
    直接调用m.lock()和m.unlock()很容易因为异常或者代码分支遗漏导致死锁,而unique_lock会在作用域结束时自动释放锁,同时condition_variable::wait()必须搭配unique_lock使用(因为wait过程中会临时释放锁,被唤醒后重新获取)。

  • 用while循环替代if判断条件(核心!):
    这是解决虚假唤醒的关键。虚假唤醒时,wait()会在没有收到生产者通知的情况下返回,如果只用if,消费者会直接尝试消费空队列,导致错误。而while循环会在每次wait返回后重新检查条件,确保队列确实有数据或者生产已经完成,只有条件满足才会继续执行。

  • 正确处理结束标志done:
    生产者完成所有生产后,需要设置done标志并调用notify_all()(避免消费者还在wait中阻塞),消费者在检查到done且队列为空时才会退出,确保所有生产的产品都被消费完毕。

  • 通知的时机:
    生产者在生产完一个数据后调用notify_one(),唤醒一个等待的消费者。注意这里不需要刻意在解锁后通知,因为unique_lock在notify后会自动解锁,不过如果是性能敏感场景,解锁后通知可能更高效(避免消费者被唤醒后还需要等待锁)。

这样修改后,你的代码就能正确处理虚假唤醒问题,稳定运行生产者消费者模型了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:09:42