std::condition_variable 是 C++ 标准库(C++11 及以上)中用于多线程同步的机制,主要用于线程间的等待-通知交互。它通常与互斥锁(std::mutex)配合使用,允许线程在某个条件未满足时进入阻塞状态,待条件满足后由其他线程唤醒,从而避免无效的忙等(busy waiting),提高程序效率。

核心作用

解决多线程环境中“线程需要等待某个条件成立才能继续执行”的场景。例如:

  • 生产者-消费者模型:消费者等待生产者生成数据后再处理;
  • 线程池:工作线程等待任务队列中有新任务时再执行。

常用成员函数

std::condition_variable 定义在 <condition_variable> 头文件中,核心函数包括:

  1. wait(unique_lock<mutex>& lock)
    使当前线程进入阻塞状态,同时释放所持有的互斥锁(允许其他线程获取锁)。当线程被唤醒时,会重新获取锁并继续执行。

  2. wait(unique_lock<mutex>& lock, Predicate pred)
    带条件的等待。等价于:

    while (!pred()) {
        wait(lock);  // 循环检查条件,处理"虚假唤醒"
    }
    
  3. notify_one()
    随机唤醒一个正在等待当前 condition_variable 的线程。

  4. notify_all()
    唤醒所有正在等待当前 condition_variable 的线程。

关键概念:虚假唤醒(Spurious Wakeups)

操作系统可能在无明确通知的情况下唤醒等待的线程(例如系统调度原因),这种情况称为“虚假唤醒”。因此,必须在唤醒后重新检查条件,通常通过循环实现(这也是带 Predicate 的 wait 重载的意义)。

使用示例:生产者-消费者模型

下面是一个简单的示例,展示如何用 std::condition_variable 协调生产者(生产数据)和消费者(消费数据):

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

std::queue<int> data_queue;  // 共享数据队列
std::mutex mtx;              // 保护队列的互斥锁
std::condition_variable cv;  // 条件变量,用于通知

// 生产者:生成数据并放入队列
void producer() {
    for (int i = 0; i < 5; ++i) {
        std::unique_lock<std::mutex> lock(mtx);  // 加锁
        data_queue.push(i);                      // 生产数据
        std::cout << "Produced: " << i << std::endl;
        lock.unlock();  // 可选:提前解锁(notify_one不需要持有锁)
        cv.notify_one(); // 通知一个等待的消费者
        std::this_thread::sleep_for(std::chrono::milliseconds(500)); // 模拟耗时
    }
}

// 消费者:从队列中取数据并处理
void consumer() {
    for (int i = 0; i < 5; ++i) {
        std::unique_lock<std::mutex> lock(mtx);  // 加锁
        
        // 等待条件:队列非空(处理虚假唤醒)
        cv.wait(lock, []{ return !data_queue.empty(); });
        
        // 消费数据
        int data = data_queue.front();
        data_queue.pop();
        std::cout << "Consumed: " << data << std::endl;
    }
}

int main() {
    std::thread prod(producer);
    std::thread cons(consumer);
    
    prod.join();
    cons.join();
    return 0;
}

输出(顺序可能因调度略有不同)

Produced: 0
Consumed: 0
Produced: 1
Consumed: 1
Produced: 2
Consumed: 2
Produced: 3
Consumed: 3
Produced: 4
Consumed: 4

注意事项

  1. 必须与 std::unique_lock 配合wait 函数要求传入 std::unique_lock<std::mutex>,因为它需要在等待时释放锁,唤醒时重新获取锁(std::lock_guard 不支持手动释放锁)。

  2. 避免死锁:通知线程(notify_one/notify_all)不需要持有锁,但等待线程必须在持有锁的情况下调用 wait

  3. 明确条件范围:条件变量本身不存储条件状态,条件通常是基于共享数据的(如示例中的队列是否为空),需通过互斥锁保护。

  4. notify_one vs notify_all

    • 只需一个线程处理时用 notify_one(更高效);
    • 所有等待线程都需处理时用 notify_all(如全局状态更新)。

std::condition_variable 是多线程同步的核心工具之一,合理使用可有效解决线程间的协作问题,避免资源竞争和无效等待。

Logo

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

更多推荐