条件变量(Condition Variable)是C++多线程中用于线程间等待与通知的同步机制,常与互斥量(mutex) 一起使用。

👉 条件变量 = 线程“等一个条件成立再继续”的工具
不满足就睡眠,满足了被别人叫醒。

为什么需要条件变量?

如果只用 mutex,线程可能要不停轮询(忙等):

while (!ready) { } // 浪费 CPU

条件变量可以:

  • 线程阻塞等待(不占 CPU)

  • 条件满足后被通知唤醒

基本使用流程(核心 4 步)

等待线程

std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, 条件);

通知线程

cv.notify_one();  // 唤醒一个
cv.notify_all();  // 唤醒全部

完整示例:生产者 – 消费者(Condition Variable)

功能说明

  • 生产者线程:不断往队列里放数据

  • 消费者线程:队列为空就等待,有数据就取

  • 使用 条件变量避免忙等

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <chrono>

std::queue<int> dataQueue;           // 共享队列
std::mutex mtx;                      // 互斥量
std::condition_variable cv;          // 条件变量
bool finished = false;               // 生产是否结束

// 生产者
void producer() {
    for (int i = 1; i <= 5; ++i) {
        {
            std::lock_guard<std::mutex> lock(mtx);
            dataQueue.push(i);
            std::cout << "Producer produced: " << i << std::endl;
        }
        cv.notify_one(); // 通知消费者
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
    }

    // 生产结束
    {
        std::lock_guard<std::mutex> lock(mtx);
        finished = true;
    }
    cv.notify_all(); // 唤醒所有等待的消费者
}

// 消费者
void consumer() {
    while (true) {
        std::unique_lock<std::mutex> lock(mtx);

        // 等待:队列非空 或 生产结束
        cv.wait(lock, [] {
            return !dataQueue.empty() || finished;
        });

        // 队列有数据 → 消费
        while (!dataQueue.empty()) {
            int value = dataQueue.front();
            dataQueue.pop();
            std::cout << "Consumer consumed: " << value << std::endl;
        }

        // 生产结束且队列为空 → 退出
        if (finished) {
            break;
        }
    }
}

int main() {
    std::thread t1(producer);
    std::thread t2(consumer);

    t1.join();
    t2.join();

    std::cout << "All done." << std::endl;
    return 0;
}

Producer produced: 1
Consumer consumed: 1
Producer produced: 2
Consumer consumed: 2
...
All done.

一、程序启动(main)

int main() {
    std::thread t1(producer);
    std::thread t2(consumer);

    t1.join();
    t2.join();
}

  • 主线程创建 生产者线程 t1

  • 主线程创建 消费者线程 t2

  • 主线程阻塞在 join(),等它们结束

二、消费者先跑(常见情况)

① consumer 线程进入 while(true)

std::unique_lock<std::mutex> lock(mtx);

  • consumer 拿到互斥锁

  • 此时队列:

  • finished = false

② consumer 调用 wait

cv.wait(lock, [] { return !dataQueue.empty() || finished; });

wait 内部发生的事(非常关键):
  1. 判断条件:

!dataQueue.empty() || finished // false

  1. 条件不成立 →

  2. 自动释放 mutex

  3. consumer 线程 进入休眠(阻塞)

👉 此时:

  • consumer ❌ 不占 CPU

  • mutex 现在是 空闲的


三、生产者开始工作

③ producer 线程第一次循环

std::lock_guard<std::mutex> lock(mtx); dataQueue.push(1);

  • producer 拿到 mutex

  • 往队列放入 1

  • 作用域结束 → mutex 自动释放

④ producer 通知

cv.notify_one(); 

  • 操作系统 唤醒一个正在 wait 的线程

  • 此时 consumer 被标记为“可运行”

⚠️ 但:consumer 还没真正跑

四、消费者被唤醒

⑤ consumer 被唤醒后

wait 做的事:

cv.wait(...) // 内部继续

重新尝试加锁 mutex(必须成功)

再次检查条件:

!dataQueue.empty() || finished // true

条件成立 → wait 返回


⑥ consumer 消费数据

while (!dataQueue.empty()) { int value = dataQueue.front(); dataQueue.pop(); }

  • 消费 1

  • 队列再次为空


五、重复这个过程

⑦ producer 继续生产

push(2) → notify push(3) → notify ...

⑧ consumer 重复

wait → 醒 → 加锁 → 消费 → 再 wait

六、生产结束

⑨ producer 设置结束标志

{ std::lock_guard<std::mutex> lock(mtx); finished = true; } cv.notify_all();

关键点:

  • 修改 finished 在锁内(线程安全)

  • notify_all() 防止 consumer 永久睡眠


七、消费者安全退出

⑩ consumer 再次醒来

cv.wait(lock, [] { return !dataQueue.empty() || finished; });

  • 此时:finished == true

  • 即使队列空,条件也成立

  • wait 返回


⑪ consumer 判断退出条件

if (finished) { break; }

  • 跳出 while(true)

  • consumer 线程结束


八、程序结束

  1. producer 线程结束

  2. consumer 线程结束

  3. join() 返回

  4. main 结束

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐