C++_condition_variable条件变量

C++11 引入的线程同步工具,用于实现"等待-通知"机制。当某个条件不满足时,线程可以阻塞等待;当条件满足时,另一个线程发出通知将其唤醒。


核心组成

条件变量必须与互斥锁配合使用,通常包含三个要素:

std::mutex mx;                    // 互斥锁,保护共享数据
std::condition_variable cv;       // 条件变量,负责等待和通知
bool condition = false;           // 共享条件(可以是任意类型的条件)

核心API

等待方:wait()

wait() 有三种形式:

// 形式一:无限等待(可能虚假唤醒)
void wait(std::unique_lock<std::mutex>& lock);

// 形式二:带谓词的无限等待(自动处理虚假唤醒)
template<class Predicate>
void wait(std::unique_lock<std::mutex>& lock, Predicate pred);

// 形式三:带超时的等待
template<class Rep, class Period>
std::cv_status wait_for(std::unique_lock<std::mutex>& lock,
                        const std::chrono::duration<Rep, Period>& rel_time);

// 形式四:带谓词和超时的等待
template<class Rep, class Period, class Predicate>
bool wait_for(std::unique_lock<std::mutex>& lock,
              const std::chrono::duration<Rep, Period>& rel_time,
              Predicate pred);

wait()内部行为:

  1. 自动释放锁 → 让其他线程有机会修改共享条件
  2. 线程进入阻塞休眠 → 不消耗 CPU
  3. 被唤醒后,自动重新获取锁 → 保证后续代码的线程安全
  4. 函数返回

通知方:notify

void notify_one();   // 唤醒一个等待线程(随机选择)
void notify_all();   // 唤醒所有等待线程

虚假唤醒(Spurious Wakeup)

这是一个非常重要的概念:线程可能在没有被通知的情况下意外醒来,这是操作系统层面的行为,C++ 标准允许这种情况发生。

虚假唤醒错误写法(使用if)
std::unique_lock<std::mutex> lock(mx);
if (!ready) {           //  虚假唤醒时,条件仍为false,但已经跳出了if
    cv.wait(lock);
}
// 继续执行——但条件其实不满足!
虚假唤醒正确写法(用while)
std::unique_lock<std::mutex> lock(mx);
while (!ready) {        // 虚假唤醒后,重新检查条件,不满足则继续等待
    cv.wait(lock);
}
// 能走到这里,说明条件一定满足
简洁语法(带谓词的 wait)
std::unique_lock<std::mutex> lock(mx);
cv.wait(lock, []{ return ready; });  //  等价于上面的 while 循环

示例

#include <iostream>
#include <thread>
#include <condition_variable>
#include <mutex>
using namespace std;
mutex mx;
condition_variable scv;
bool ready = false;

void print_id(int id) {
	unique_lock<mutex> lck(mx);
	while (!ready) scv.wait(lck); // 如果标志位为false,则阻塞当前线程,直到标志位为true,才继续执行
	cout << "thread " << id << endl;
}
void RunFunc() {
	unique_lock<mutex> lck(mx);
	ready = true; // 设置标志位为true,表示线程可以继续执行
	scv.notify_all(); // 唤醒所有等待的线程
}
int main()
{
	thread thrs[5];
	for (int i = 0; i < 5; i++) {
		thrs[i] = thread(print_id, i);
	}
	cout << "5 threads ready to race...\n";
	RunFunc();

	for (auto& t : thrs) {  // 遍历线程数组中的每一个线程
		t.join();
	}
	return 0;
}

C++_condition_variable条件变量
C++_condition_variable条件变量

常见陷阱

  • 忘记加锁就修改条件 → 数据竞争。
  • notify 再改条件 → 等待方醒来发现条件不满足,继续等待(可能永久等待)。
  • if 代替 while → 虚假唤醒导致逻辑错误。
  • lock_guard 代替 unique_lock → 编译报错,wait() 要求 unique_lock
  • notify 时仍持有锁 → 被唤醒的线程立即阻塞,性能下降。

总结

std::condition_variable 的本质就是一个线程间的"消息通知"机制:

  • 等待方:wait() → 释放锁 + 休眠 + 被唤醒 + 重新加锁。
  • 通知方:改条件 → notify_one() / notify_all()
  • 永远用 while 或带谓词的 wait() 来防止虚假唤醒。
  • 必须配合 std::unique_lock<std::mutex> 使用。

c++越学越不懂了呀,需借助AI分析别人的c++代码T.T~

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐