std::condition_variable
一、核心原理速览
- 本质:线程同步原语,实现阻塞-通知机制,避免忙等待
- 强制要求:必须与
std::unique_lock<std::mutex>配合使用(wait需要原子解锁/加锁) - 核心函数:
wait(lock):阻塞直到被通知(存在虚假唤醒)wait(lock, pred):阻塞直到被通知且pred()为true(推荐,自动处理虚假唤醒)notify_one():唤醒一个等待线程notify_all():唤醒所有等待线程wait_for()/wait_until():带超时的等待
二、入门级示例
示例1:最基础单生产者-单消费者
cpp
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
int data = 0;
bool ready = false;
void producer() {
std::lock_guard<std::mutex> lock(mtx);
data = 42;
ready = true;
cv.notify_one();
}
void consumer() {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return ready; });
std::cout << "Received: " << data << std::endl;
}
int main() {
std::thread t1(producer);
std::thread t2(consumer);
t1.join();
t2.join();
return 0;
}
核心知识点:条件变量最基本的通知-等待流程,生产者修改共享状态后通知消费者。
示例2:虚假唤醒演示与正确写法
错误写法(无谓词,可能因虚假唤醒导致逻辑错误)
cpp
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void worker() {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock);
std::cout << "Worker running" << std::endl;
}
int main() {
std::thread t(worker);
std::this_thread::sleep_for(std::chrono::seconds(1));
t.join();
return 0;
}
正确写法(带谓词,自动处理虚假唤醒)
cpp
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void worker() {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return ready; });
std::cout << "Worker running" << std::endl;
}
int main() {
std::thread t(worker);
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::lock_guard<std::mutex> lock(mtx);
ready = true;
}
cv.notify_one();
t.join();
return 0;
}
核心知识点:虚假唤醒是操作系统的正常行为,必须通过谓词或循环检查条件来规避。
三、进阶级示例
示例3:多生产者-多消费者(有界队列)
cpp
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <chrono>
std::mutex mtx;
std::condition_variable cv;
std::queue<int> q;
const int MAX_SIZE = 3;
void producer(int id) {
for (int i = 0; i < 5; ++i) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return q.size() < MAX_SIZE; });
q.push(i);
std::cout << "Producer " << id << " produced " << i << std::endl;
lock.unlock();
cv.notify_all();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
void consumer(int id) {
while (true) {
std::unique_lock<std::mutex> lock(mtx);
if (cv.wait_for(lock, std::chrono::seconds(2), []{ return!q.empty(); })) {
int val = q.front();
q.pop();
std::cout << "Consumer " << id << " consumed " << val << std::endl;
lock.unlock();
cv.notify_all();
if (val == 4) break;
} else {
std::cout << "Consumer " << id << " timeout" << std::endl;
break;
}
}
}
int main() {
std::thread p1(producer, 1);
std::thread p2(producer, 2);
std::thread c1(consumer, 1);
std::thread c2(consumer, 2);
p1.join();
p2.join();
c1.join();
c2.join();
return 0;
}
核心知识点 :处理多线程竞争下的队列满/空状态,使用 notify_all 唤醒所有等待线程,wait_for 避免永久阻塞。
示例4:超时等待(wait_for vs wait_until)
cpp
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void worker1() {
std::unique_lock<std::mutex> lock(mtx);
if (cv.wait_for(lock, std::chrono::seconds(2), []{ return ready; })) {
std::cout << "Worker1: Ready" << std::endl;
} else {
std::cout << "Worker1: Timeout" << std::endl;
}
}
void worker2() {
std::unique_lock<std::mutex> lock(mtx);
auto deadline = std::chrono::system_clock::now() + std::chrono::seconds(3);
if (cv.wait_until(lock, deadline, []{ return ready; })) {
std::cout << "Worker2: Ready" << std::endl;
} else {
std::cout << "Worker2: Timeout" << std::endl;
}
}
int main() {
std::thread t1(worker1);
std::thread t2(worker2);
std::this_thread::sleep_for(std::chrono::seconds(2));
{
std::lock_guard<std::mutex> lock(mtx);
ready = true;
}
cv.notify_all();
t1.join();
t2.join();
return 0;
}
核心知识点 :wait_for 等待相对时间,wait_until 等待绝对时间点,两者都支持谓词参数。
示例5:notify_all 批量唤醒场景
cpp
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <chrono>
std::mutex mtx;
std::condition_variable cv;
bool start = false;
void worker(int id) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return start; });
std::cout << "Worker " << id << " started" << std::endl;
}
int main() {
std::vector<std::thread> workers;
for (int i = 0; i < 5; ++i) {
workers.emplace_back(worker, i);
}
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "Main: Starting all workers" << std::endl;
{
std::lock_guard<std::mutex> lock(mtx);
start = true;
}
cv.notify_all();
for (auto& t : workers) {
t.join();
}
return 0;
}
核心知识点 :当多个线程需要等待同一个全局信号时,必须使用 notify_all,否则只会唤醒一个线程。
四、精通级示例
示例6:通用线程安全队列(双条件变量优化)
cpp
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <vector>
template <typename T>
class ThreadSafeQueue {
public:
explicit ThreadSafeQueue(size_t max_size) : max_size_(max_size) {}
void push(T item) {
std::unique_lock<std::mutex> lock(mutex_);
not_full_.wait(lock, [this]{ return queue_.size() < max_size_; });
queue_.push(std::move(item));
not_empty_.notify_one();
}
T pop() {
std::unique_lock<std::mutex> lock(mutex_);
not_empty_.wait(lock, [this]{ return!queue_.empty(); });
T item = std::move(queue_.front());
queue_.pop();
not_full_.notify_one();
return item;
}
size_t size() const {
std::lock_guard<std::mutex> lock(mutex_);
return queue_.size();
}
bool empty() const {
std::lock_guard<std::mutex> lock(mutex_);
return queue_.empty();
}
private:
std::queue<T> queue_;
mutable std::mutex mutex_;
std::condition_variable not_empty_;
std::condition_variable not_full_;
size_t max_size_;
};
void producer(ThreadSafeQueue<int>& q, int id) {
for (int i = 0; i < 5; ++i) {
q.push(i);
std::cout << "Producer " << id << " pushed " << i << std::endl;
}
}
void consumer(ThreadSafeQueue<int>& q, int id) {
for (int i = 0; i < 5; ++i) {
int val = q.pop();
std::cout << "Consumer " << id << " popped " << val << std::endl;
}
}
int main() {
ThreadSafeQueue<int> q(3);
std::thread p1(producer, std::ref(q), 1);
std::thread p2(producer, std::ref(q), 2);
std::thread c1(consumer, std::ref(q), 1);
std::thread c2(consumer, std::ref(q), 2);
p1.join();
p2.join();
c1.join();
c2.join();
return 0;
}
核心知识点 :使用两个独立条件变量分别控制队列非空和非满,避免 notify_all 带来的惊群效应,大幅提升多线程场景下的性能。
示例7:一次性事件(One-shot Event)
cpp
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <vector>
class OneShotEvent {
public:
void signal() {
std::lock_guard<std::mutex> lock(mtx_);
signaled_ = true;
cv_.notify_all();
}
void wait() {
std::unique_lock<std::mutex> lock(mtx_);
cv_.wait(lock, [this]{ return signaled_; });
}
private:
std::mutex mtx_;
std::condition_variable cv_;
bool signaled_ = false;
};
void worker(OneShotEvent& event, int id) {
std::cout << "Worker " << id << " waiting for signal" << std::endl;
event.wait();
std::cout << "Worker " << id << " received signal" << std::endl;
}
int main() {
OneShotEvent event;
std::vector<std::thread> workers;
for (int i = 0; i < 3; ++i) {
workers.emplace_back(worker, std::ref(event), i);
}
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "Main: Sending signal" << std::endl;
event.signal();
for (auto& t : workers) {
t.join();
}
return 0;
}
核心知识点 :实现一次性通知机制,条件一旦满足就永远为true,后续调用 wait 会立即返回,适合初始化完成、程序启动信号等场景。
示例8:线程屏障(Barrier)
cpp
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <vector>
class Barrier {
public:
explicit Barrier(size_t count) : count_(count), waiting_(0), generation_(0) {}
void wait() {
std::unique_lock<std::mutex> lock(mtx_);
size_t gen = generation_;
if (++waiting_ == count_) {
waiting_ = 0;
generation_++;
cv_.notify_all();
} else {
cv_.wait(lock, [this, gen]{ return gen!= generation_; });
}
}
private:
std::mutex mtx_;
std::condition_variable cv_;
size_t count_;
size_t waiting_;
size_t generation_;
};
void worker(Barrier& barrier, int id) {
std::cout << "Worker " << id << " phase 1" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100 * id));
barrier.wait();
std::cout << "Worker " << id << " phase 2" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100 * id));
barrier.wait();
std::cout << "Worker " << id << " done" << std::endl;
}
int main() {
Barrier barrier(3);
std::vector<std::thread> workers;
for (int i = 0; i < 3; ++i) {
workers.emplace_back(worker, std::ref(barrier), i);
}
for (auto& t : workers) {
t.join();
}
return 0;
}
核心知识点 :实现多线程同步点,所有线程必须到达屏障后才能继续执行。通过 generation 计数器支持多次屏障同步。
示例9:简化版线程池
cpp
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <vector>
#include <functional>
class ThreadPool {
public:
explicit ThreadPool(size_t num_threads) : stop_(false) {
for (size_t i = 0; i < num_threads; ++i) {
workers_.emplace_back([this]{
while (true) {
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(mtx_);
cv_.wait(lock, [this]{ return stop_ ||!tasks_.empty(); });
if (stop_ && tasks_.empty()) {
return;
}
task = std::move(tasks_.front());
tasks_.pop();
}
task();
}
});
}
}
void submit(std::function<void()> task) {
{
std::lock_guard<std::mutex> lock(mtx_);
tasks_.push(std::move(task));
}
cv_.notify_one();
}
~ThreadPool() {
{
std::lock_guard<std::mutex> lock(mtx_);
stop_ = true;
}
cv_.notify_all();
for (auto& t : workers_) {
t.join();
}
}
private:
std::vector<std::thread> workers_;
std::queue<std::function<void()>> tasks_;
std::mutex mtx_;
std::condition_variable cv_;
bool stop_;
};
int main() {
ThreadPool pool(4);
for (int i = 0; i < 10; ++i) {
pool.submit([i]{
std::cout << "Task " << i << " executed by thread " << std::this_thread::get_id() << std::endl;
});
}
std::this_thread::sleep_for(std::chrono::seconds(1));
return 0;
}
核心知识点:条件变量是线程池的核心同步机制,工作线程等待任务队列非空,主线程提交任务后唤醒一个工作线程执行。
五、常见陷阱与反例
反例1:使用 std::lock_guard 代替 std::unique_lock
cpp
// 编译错误!lock_guard 不支持解锁/重新加锁
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void worker() {
std::lock_guard<std::mutex> lock(mtx);
cv.wait(lock);
}
int main() {
std::thread t(worker);
t.join();
return 0;
}
反例2:通知丢失
cpp
// 线程会永久阻塞,因为通知在 wait 之前发送
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void worker() {
std::this_thread::sleep_for(std::chrono::seconds(1));
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock);
}
int main() {
std::thread t(worker);
{
std::lock_guard<std::mutex> lock(mtx);
ready = true;
}
cv.notify_one();
t.join();
return 0;
}
解决方法 :始终使用带谓词的 wait,它会在阻塞前先检查条件。
反例3:持有锁时调用 notify
cpp
// 虽然不会死锁,但性能极差
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void worker() {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return ready; });
std::cout << "Worker running" << std::endl;
}
int main() {
std::thread t(worker);
std::this_thread::sleep_for(std::chrono::seconds(1));
std::lock_guard<std::mutex> lock(mtx);
ready = true;
cv.notify_one(); // 持有锁时通知,被唤醒的线程会立即阻塞
std::this_thread::sleep_for(std::chrono::seconds(1));
return 0;
}
解决方法 :先解锁互斥量,再调用 notify。
六、实践总结
- 永远使用带谓词的
wait,这是避免虚假唤醒和通知丢失的唯一可靠方法 - 必须使用
std::unique_lock与条件变量配合 - 先解锁再通知,避免被唤醒的线程立即阻塞在锁上
- 优先使用
notify_one而非notify_all,减少惊群效应 - 避免在临界区执行耗时操作,缩小锁的粒度
- 使用双条件变量 优化生产者-消费者模型的性能
为什么要用 std::condition_variable?
std::condition_variable 是 C++ 中用于线程高效协作的同步原语,核心价值是解决两个关键问题:
一、避免「忙等待(Busy Waiting)」,节省 CPU 资源
反例:纯轮询(忙等待)的糟糕性能
假设我们用一个全局标志位 ready 来同步两个线程,消费者线程会不断循环检查标志位:
cpp
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
std::mutex mtx;
bool ready = false;
void consumer() {
while (true) {
std::lock_guard<std::mutex> lock(mtx);
if (ready) {
std::cout << "Data received!" << std::endl;
break;
}
// 即使加了 sleep,仍会浪费 CPU 时间片,且响应延迟
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
void producer() {
std::this_thread::sleep_for(std::chrono::seconds(1));
std::lock_guard<std::mutex> lock(mtx);
ready = true;
}
int main() {
std::thread t1(consumer);
std::thread t2(producer);
t1.join();
t2.join();
return 0;
}
问题:
- 消费者线程即使在
sleep,仍会周期性唤醒并占用 CPU 检查条件。 - 若
sleep时间太长,会导致响应延迟;若太短,CPU 浪费更严重。
条件变量的解决方案
std::condition_variable 让线程真正休眠,直到被其他线程显式唤醒,完全不占用 CPU 时间片:
cpp
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void consumer() {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return ready; }); // 线程在此休眠,不占用 CPU
std::cout << "Data received!" << std::endl;
}
void producer() {
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::lock_guard<std::mutex> lock(mtx);
ready = true;
}
cv.notify_one(); // 显式唤醒消费者
}
int main() {
std::thread t1(consumer);
std::thread t2(producer);
t1.join();
t2.join();
return 0;
}
优势:
- 消费者线程在
wait()时会自动解锁互斥锁并进入阻塞状态,CPU 完全释放给其他线程。 - 生产者线程
notify_one()后,消费者线程被唤醒、重新加锁并检查条件,响应即时且无 CPU 浪费。
二、实现「原子性的解锁-等待-加锁」,避免竞态条件
wait() 函数的内部逻辑是原子操作:
- 解锁互斥锁(让其他线程能修改共享状态)。
- 阻塞当前线程,等待通知。
- 被唤醒后,重新加锁并检查条件(避免虚假唤醒)。
如果没有这个原子性,可能会出现「通知丢失」的致命问题:
假设线程 A 先检查条件(不满足),然后准备休眠;但在它真正休眠前,线程 B 修改了条件并发送了通知------此时线程 A 还没开始等待,通知就丢失了,线程 A 会永久阻塞。
std::condition_variable 的原子性 wait() 完美解决了这个问题。
核心使用场景
场景 1:生产者-消费者模型(最经典)
- 需求:一个/多个线程生产数据放入队列,一个/多个线程从队列取数据处理。
- 条件变量的作用 :
- 队列空时,消费者线程休眠,等待生产者放入数据。
- 队列满时,生产者线程休眠,等待消费者取出数据。
- 典型应用:日志系统(生产者写日志,消费者落盘)、视频流处理(生产者推流,消费者解码)。
场景 2:线程池
- 需求:固定数量的工作线程等待任务队列,有任务时执行,无任务时休眠。
- 条件变量的作用 :
- 任务队列为空时,所有工作线程休眠。
- 主线程提交任务后,唤醒一个工作线程执行。
- 典型应用:Web 服务器处理并发请求、后台任务调度系统。
场景 3:一次性事件通知(One-shot Event)
- 需求:某个全局事件(如系统初始化完成、资源加载完成)发生后,通知所有等待的线程开始工作。
- 条件变量的作用 :
- 事件未发生时,所有工作线程休眠。
- 事件发生后,通过
notify_all()批量唤醒所有线程。
- 典型应用:游戏引擎的「资源加载完成后开始渲染」、分布式系统的「所有节点就绪后启动任务」。
场景 4:线程屏障(Barrier)
- 需求:多个线程分阶段执行任务,所有线程必须到达某个「同步点」后,才能一起进入下一个阶段。
- 条件变量的作用 :
- 未到达同步点的线程休眠。
- 最后一个线程到达后,唤醒所有线程继续执行。
- 典型应用:并行计算(如矩阵乘法分块处理,所有块计算完后合并结果)、压力测试(所有虚拟用户准备好后同时发起请求)。
场景 5:读写锁的实现(进阶)
- 需求:多个线程可以同时读共享数据,但写操作必须独占,且写操作优先级高于读操作。
- 条件变量的作用 :
- 有写线程等待时,新的读线程休眠,等待写线程完成。
- 写线程完成后,唤醒所有等待的读线程或下一个写线程。
什么时候不用 std::condition_variable?
- 简单的互斥访问 :仅需保护共享数据不被并发修改,用
std::mutex即可。 - 一次性任务返回结果 :用
std::future/std::promise更简洁,无需手动管理条件变量和标志位。 - 周期性任务调度 :用定时器库(如
std::chrono+ 线程 sleep)更合适。
场景代码补充
场景1:生产者-消费者模型(双条件变量优化)
cpp
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <vector>
template <typename T>
class BoundedQueue {
public:
explicit BoundedQueue(size_t capacity) : capacity_(capacity) {}
void push(T item) {
std::unique_lock<std::mutex> lock(mtx_);
not_full_.wait(lock, [this]{ return queue_.size() < capacity_; });
queue_.push(std::move(item));
not_empty_.notify_one();
}
T pop() {
std::unique_lock<std::mutex> lock(mtx_);
not_empty_.wait(lock, [this]{ return!queue_.empty(); });
T item = std::move(queue_.front());
queue_.pop();
not_full_.notify_one();
return item;
}
size_t size() const {
std::lock_guard<std::mutex> lock(mtx_);
return queue_.size();
}
private:
std::queue<T> queue_;
mutable std::mutex mtx_;
std::condition_variable not_empty_;
std::condition_variable not_full_;
size_t capacity_;
};
void producer(BoundedQueue<int>& q, int id) {
for (int i = 0; i < 5; ++i) {
q.push(i);
std::cout << "Producer " << id << " produced: " << i << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
}
void consumer(BoundedQueue<int>& q, int id) {
for (int i = 0; i < 5; ++i) {
int val = q.pop();
std::cout << "Consumer " << id << " consumed: " << val << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
int main() {
BoundedQueue<int> q(3);
std::vector<std::thread> producers;
std::vector<std::thread> consumers;
for (int i = 0; i < 2; ++i) {
producers.emplace_back(producer, std::ref(q), i);
}
for (int i = 0; i < 2; ++i) {
consumers.emplace_back(consumer, std::ref(q), i);
}
for (auto& t : producers) t.join();
for (auto& t : consumers) t.join();
return 0;
}
场景2:简化版线程池
cpp
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <vector>
#include <functional>
#include <chrono>
class ThreadPool {
public:
explicit ThreadPool(size_t num_threads) : stop_(false) {
for (size_t i = 0; i < num_threads; ++i) {
workers_.emplace_back([this]{
while (true) {
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(mtx_);
cv_.wait(lock, [this]{ return stop_ ||!tasks_.empty(); });
if (stop_ && tasks_.empty()) return;
task = std::move(tasks_.front());
tasks_.pop();
}
task();
}
});
}
}
void submit(std::function<void()> task) {
{
std::lock_guard<std::mutex> lock(mtx_);
tasks_.push(std::move(task));
}
cv_.notify_one();
}
~ThreadPool() {
{
std::lock_guard<std::mutex> lock(mtx_);
stop_ = true;
}
cv_.notify_all();
for (auto& t : workers_) t.join();
}
private:
std::vector<std::thread> workers_;
std::queue<std::function<void()>> tasks_;
std::mutex mtx_;
std::condition_variable cv_;
bool stop_;
};
int main() {
ThreadPool pool(4);
for (int i = 0; i < 10; ++i) {
pool.submit([i]{
std::cout << "Task " << i << " running on thread "
<< std::this_thread::get_id() << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
});
}
std::this_thread::sleep_for(std::chrono::seconds(2));
return 0;
}
场景3:一次性事件通知
cpp
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <chrono>
class OneShotEvent {
public:
void signal() {
std::lock_guard<std::mutex> lock(mtx_);
signaled_ = true;
cv_.notify_all();
}
void wait() {
std::unique_lock<std::mutex> lock(mtx_);
cv_.wait(lock, [this]{ return signaled_; });
}
private:
std::mutex mtx_;
std::condition_variable cv_;
bool signaled_ = false;
};
void worker(OneShotEvent& event, int id) {
std::cout << "Worker " << id << " waiting for start signal..." << std::endl;
event.wait();
std::cout << "Worker " << id << " started working!" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100 * id));
std::cout << "Worker " << id << " finished!" << std::endl;
}
int main() {
OneShotEvent start_event;
std::vector<std::thread> workers;
for (int i = 0; i < 5; ++i) {
workers.emplace_back(worker, std::ref(start_event), i);
}
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "\nMain thread sending start signal!\n" << std::endl;
start_event.signal();
for (auto& t : workers) t.join();
return 0;
}
场景4:可复用线程屏障
cpp
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <chrono>
class Barrier {
public:
explicit Barrier(size_t count) : count_(count), waiting_(0), generation_(0) {}
void wait() {
std::unique_lock<std::mutex> lock(mtx_);
size_t gen = generation_;
if (++waiting_ == count_) {
waiting_ = 0;
generation_++;
cv_.notify_all();
} else {
cv_.wait(lock, [this, gen]{ return gen!= generation_; });
}
}
private:
std::mutex mtx_;
std::condition_variable cv_;
size_t count_;
size_t waiting_;
size_t generation_;
};
void worker(Barrier& barrier, int id) {
std::cout << "Worker " << id << " entering phase 1" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100 * id));
barrier.wait();
std::cout << "Worker " << id << " entering phase 2" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100 * id));
barrier.wait();
std::cout << "Worker " << id << " completed all phases" << std::endl;
}
int main() {
Barrier barrier(3);
std::vector<std::thread> workers;
for (int i = 0; i < 3; ++i) {
workers.emplace_back(worker, std::ref(barrier), i);
}
for (auto& t : workers) t.join();
return 0;
}
场景5:写优先读写锁实现
cpp
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <chrono>
class ReadWriteLock {
public:
void lock_read() {
std::unique_lock<std::mutex> lock(mtx_);
read_cv_.wait(lock, [this]{ return write_waiting_ == 0 &&!writing_; });
readers_++;
}
void unlock_read() {
std::lock_guard<std::mutex> lock(mtx_);
readers_--;
if (readers_ == 0 && write_waiting_ > 0) {
write_cv_.notify_one();
}
}
void lock_write() {
std::unique_lock<std::mutex> lock(mtx_);
write_waiting_++;
write_cv_.wait(lock, [this]{ return readers_ == 0 &&!writing_; });
write_waiting_--;
writing_ = true;
}
void unlock_write() {
std::lock_guard<std::mutex> lock(mtx_);
writing_ = false;
if (write_waiting_ > 0) {
write_cv_.notify_one();
} else {
read_cv_.notify_all();
}
}
private:
std::mutex mtx_;
std::condition_variable read_cv_;
std::condition_variable write_cv_;
int readers_ = 0;
int write_waiting_ = 0;
bool writing_ = false;
};
ReadWriteLock rw_lock;
int shared_data = 0;
void reader(int id) {
for (int i = 0; i < 3; ++i) {
rw_lock.lock_read();
std::cout << "Reader " << id << " read: " << shared_data << std::endl;
rw_lock.unlock_read();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
void writer(int id) {
for (int i = 0; i < 2; ++i) {
rw_lock.lock_write();
shared_data++;
std::cout << "Writer " << id << " wrote: " << shared_data << std::endl;
rw_lock.unlock_write();
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
}
int main() {
std::vector<std::thread> readers;
std::vector<std::thread> writers;
for (int i = 0; i < 5; ++i) {
readers.emplace_back(reader, i);
}
for (int i = 0; i < 2; ++i) {
writers.emplace_back(writer, i);
}
for (auto& t : readers) t.join();
for (auto& t : writers) t.join();
return 0;
}