首先写一个死锁
两个线程a1、a2,a是共享资源,初始值为0。a1是生产者,访问共享资源并对它加一,a2是消费者,访问共享资源,直到非零,打印出来。
一个问题是,当a2首先访问共享资源,并对此上锁时,a1无法访问a,更无法修改它。此时a2进入死循环,造成死锁。
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
int a = 0;
mutex mt;
void a1(){
unique_lock<std::mutex> lck(mt);
a++;
}
void a2(){
unique_lock<std::mutex> lck(mt);
while (a == 0){}
cout << a << endl;
}
void main(){
thread th1(a2);
thread th2(a1);
th1.join();
th2.join();
}
解决死锁的办法就是用条件变量。
使用条件变量
当线程a2判断资源不满足条件时,并不是直接等待,而是将锁挂在一个条件变量上,在这个过程中,会自动执行mutex.unlock(),释放锁。a1检测到锁可用时,拿到锁的权限,访问a并做修改,然后条件变量通过notify_all()函数唤醒线程,注意的是,通知的过程并不释放锁,直到执行mutex.unlock()。线程a1结束释放锁,a1就能拿到锁,访问资源。
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std;
int a = 0;
mutex mt;
condition_variable cv;
void a1(){
unique_lock<std::mutex> lck(mt);
a++;
cv.notify_all();
}
void a2(){
unique_lock<std::mutex> lck(mt);
while (a == 0){
cv.wait(lck);
}
cout << a << endl;
}
void main(){
thread th1(a2);
thread th2(a1);
th1.join();
th2.join();
}
unique_lockstd::mutex 是对mutex上锁,解锁的封装,代码块结束之后,自动执行unclock()。