转自:https://www.cnblogs.com/fenghualong/p/13855360.html
1.介绍
condition_variable类似于信号量机制,实现了线程的等待和唤醒。
- wait() :阻塞等待的同时释放锁(原子操作),还可以添加阻塞判断函数,详见代码
- notify_all() : 唤醒所有阻塞等待的线程
- notify_one(): 唤醒某一个等待的线程
2.例子
锁+条件变量 实现等待唤醒。
#include <condition_variable>
#include <mutex>
#include <thread>
std::mutex mylock;
std::condition_variable condVar;
bool dataReady{false};
void waitingForWork() {
std::cout << "Waiting ..." << std::endl;
std::unique_lock<std::mutex> l(mylock); // 加了unique_lock锁
condVar.wait(l, []{return dataReady;}); // (4)
std::cout << "Running ..." << std::endl;
}
void setDataReady() {
{
std::lock_guard<std::mutex> l{mylock}; // 加了lock_guard锁
dataReady = true;
}
std::cout << "Data prepared, notify one" << std::endl;
condVar.notify_one(); // (3)
}
int main(int argc, char const *argv[])
{
std::cout << "==========Begin==========" << std::endl;
std::thread t1(waitingForWork); // (1)
std::thread t2(setDataReady); // (2)
t1.join();
t2.join();
std::cout << "===========End===========" << std::endl;
cout<<endl;
return 0;
}
// 运行结果
-> % ./main
==========Begin==========
Waiting ...
Data prepared, notify one
Running ...
===========End===========
如果不用锁和等待条件控制,可能会导致虚假唤醒和唤醒丢失问题。
2.1 wait函数原理
转自chatgpt
template<typename Predicate>
void wait(std::unique_lock<std::mutex>& lock, Predicate pred) {
while (!pred()) {// 判断条件,条件返回false
pthread_mutex_unlock(lock.mutex()->native_handle()); // 解锁unique_lock
pthread_cond_wait(&cv, lock.mutex()->native_handle());// 等待唤醒
pthread_mutex_lock(lock.mutex()->native_handle()); // 加锁
}
}
- 外部锁定互斥量: 当调用
wait
函数时,互斥量已经被std::unique_lock
锁定。std::unique_lock
提供了对互斥量的独占访问。 - 解锁互斥量并等待:
wait
函数会临时解锁互斥量,然后使当前线程进入阻塞状态,等待条件变量的通知。这一步骤是原子操作,确保在解锁和进入等待状态之间没有竞态条件。内部实现可能会调用互斥量的unlock
方法和操作系统提供的等待机制。 - 被唤醒后重新锁定互斥量: 当条件变量被通知(通过
notify_one
或notify_all
),被阻塞的线程会被唤醒。在被唤醒后,wait
函数会重新锁定互斥量。 - 检查条件并继续执行: 唤醒后,线程会检查条件是否满足。如果条件仍然不满足,线程会再次进入等待状态。否则,
wait
函数返回,线程继续执行后续的代码。
3.用条件变量实现信号量
https://blog.csdn.net/qq_24447809/article/details/115906017
#pragma once
#include<mutex>
#include<condition_variable>
class semaphore {
public:
semaphore(long count = 0) :count(count) {}
void wait() {
std::unique_lock<std::mutex>lock(mx);
cond.wait(lock, [&]() {return count > 0; });
--count;
}
void signal() {
std::unique_lock<std::mutex>lock(mx);
++count;
cond.notify_one();
}
private:
std::mutex mx;
std::condition_variable cond;
long count;
};