两个条件变量,两个mutex锁,异步同时运行,当两个控制变量均为真时,才做下一步的处理
注意处理条件变量的虚假唤醒
workerC错误写法
提前A,B都上锁了,当等待在A条件变量上时,A锁释放,cv1.wait(lkA)之后的代码是不会执行的,就意味着,B一直在上锁状态,那么workerB想要上锁给赋值,那么就会死锁了,workerB一直拿不到锁就死等。
想象一下,如果workerB是UI线程,workerC是多线程异步,UI就卡死了!
workerC正确写法
两个条件变量的等待要顺序执行,A上锁,等待在A条件变量上,B上锁,等待在B条件变量上。
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx1, mtx2;
std::condition_variable cv1, cv2;
bool conditionA = false, conditionB = false;
void workerA() {
std::unique_lock<std::mutex> lk(mtx1);
conditionA = true; // 设置条件A为真
lk.unlock();
cv1.notify_one(); // 通知可能等待在cv1上的线程
}
void workerB() {
std::unique_lock<std::mutex> lk(mtx2);
conditionB = true; // 设置条件B为真
lk.unlock();
cv2.notify_one(); // 通知可能等待在cv2上的线程
}
//workerC这么写是错误的!提前A,B都上锁了,当等待在A条件变量上时,A锁释放,cv1.wait(lkA)之后的代码是不会执行的,
//就意味着,B一直在上锁状态,那么workerB想要上锁给赋值,那么就会死锁了,workerB一直拿不到锁就死等。
//想象一下,workerB是UI线程,workerC是多线程异步,UI就卡死了!
void workerC() {
std::unique_lock<std::mutex> lkA(mtx1), lkB(mtx2);
while (!conditionA || !conditionB) { // 检查两个条件是否都为真
//if(条件为假)
// 条件变量.wait();
//这么写是为了防止条件变量虚假唤醒 导致后面本不该运行的逻辑运行了
if (!conditionA)
cv1.wait(lkA);
if (!conditionB)
cv2.wait(lkB);
}
lkA.unlock();
lkB.unlock();
// 在这里执行当两个条件都为真时的业务处理
std::cout << "Both conditions are true. Processing..." << std::endl;
//TODO...
}
//正确的workerC写法
//两个条件变量的等待要顺序执行
void workerC() {
while (!conditionA || !conditionB) { // 检查两个条件是否都为真
//这么写是为了防止条件变量虚假唤醒 导致后面本不该运行的逻辑运行了
std::unique_lock<std::mutex> lkA(mtx1);
if (!conditionA)
cv1.wait(lkA);//wait()会释放锁,并且后面的代码不会执行
lkA.unlock();
std::unique_lock<std::mutex> lkB(mtx2);;
if (!conditionB)
cv2.wait(lkB);
lkB.unlock();
}
// 在这里执行当两个条件都为真时的业务处理
std::cout << "Both conditions are true. Processing..." << std::endl;
//TODO...
}
int main() {
std::thread t3(workerC);
std::thread t1(workerA);
std::thread t2(workerB);
t1.join();
t2.join();
t3.join();
return 0;
}