一. std::condition_variable是什么?
std::condition_variable
是 C++ 标准库提供的一个线程同步的工具,用于实现线程间的条件变量等待和通知机制。 条件变量的发生通常与某个共享变量的状态改变相关。 在多线程编程中,条件变量通常和互斥锁(std::mutex
)一起使用,以避免死锁等问题。
二.用法
其常见用法如下:
1.定义std::condition_variable
对象
std::condition_variable cv;
2.定义一个互斥锁对象
std::mutex m;
3.定义一个bool类型变量作为条件,通常与互斥锁一起使用
bool condition = false;
4.等待条件变量的通知
std::unique_lock<std::mutex> lk(m);
while (!condition) {
cv.wait(lk); // 释放锁并等待通知
}
// 唤醒后继续执行
在等待时,std::condition_variable::wait()
函数会自动释放互斥锁并将线程挂起,等待其他线程通过std::condition_variable::notify_one()
或std::condition_variable::notify_all()
函数发出通知后唤醒线程。
唤醒后,std::unique_lock
会重新锁定互斥锁,线程继续执行。
5.发送条件变量的通知
std::unique_lock<std::mutex> lk(m);
condition = true;
cv.notify_one(); // 发送通知
在发送通知时,必须先获取互斥锁,并修改条件变量的状态后才能发送通知。
需要注意的是:
std::condition_variable
一般需要和std::unique_lock
一起使用,以避免竞态条件的出现。
此外,线程在等待条件变量时,可能会出现虚假唤醒的情况,因此应该使用while循环检查条件变量的状态,而不是if语句。
三.示例
std::condition_variable的用法通常是与 std::unique_lock , std::mutex 一起使用。
可以通过以下步骤来使用 std::condition_variable :
- 创建std::mutex对象来保护共享资源。
- 创建std::condition_variable对象。
- 在需要等待共享资源的线程中,使用std::unique_lock, std::mutex 锁住共享资源,并使用std::condition_variable的wait()函数来阻塞线程等待通知。
- 在修改共享资源的线程中,修改共享资源,并使用std::condition_variable的notify_one()或notify_all()函数来通知等待的线程。
- 等待的线程被唤醒后,使用std::unique_lock, std::mutex 锁住共享资源,并检查共享资源是否已经被修改。
下面是一个使用std::condition_variable的示例:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex m;
std::condition_variable cv;
bool ready = false;
void worker_thread() {
// 等待主线程的信号
std::unique_lock<std::mutex> lock(m);
while(!ready) {
cv.wait(lock);
}
// 做一些工作
std::cout << "Worker thread is working" << std::endl;
}
int main() {
// 创建工作线程
std::thread worker(worker_thread);
// 做一些工作
std::cout << "Main thread is doing something" << std::endl;
// 发送信号给工作线程
{
std::lock_guard<std::mutex> lock(m);
ready = true;
}
cv.notify_one();
// 等待工作线程完成
worker.join();
return 0;
}
运行后:
在这个例子中,主线程和工作线程共享了一个bool型变量ready,用来表示工作线程是否可以开始工作。主线程先打印一条消息,然后发送信号给工作线程。工作线程在启动后使用std::unique_lock, std::mutex 锁住共享资源ready,并在while循环中等待信号。一旦收到信号,工作线程就会解锁并开始工作。主线程等待工作线程完成后退出。