避免多个线程同时访问共享资源,避免数据竞争,提供线程间同步。
互斥锁mutex
-
lock()上锁
-
unlock解锁
-
recursive_mutex递归锁:同一个线程可以获取多次锁,不会产生死锁。
锁管理者:
-
lock_guard锁管理者:对象构造时加锁、析构时解锁
-
scoped_lock:用于多个互斥体的免死锁RALL封装器对象构造时加锁、析构时解锁
-
unique_lock:实现可移动的互斥体所有权包装器(可以把锁解锁取下来)
条件变量
获得锁(资源)若条件不满足:条件变量wait解锁将线程放到条件变量队列中。notify唤醒后加锁放入互斥队列中。
唤醒:
-
notify_one:唤醒一个
-
notify_all:唤醒全部
等待:
-
wait:阻塞当前线程,直到条件变量被唤醒
-
wait_for:指定时长时限后
-
wait_until:指定时间点
wait分四步:
-
unlock互斥锁
-
阻塞当前线程
-
mut.lock(再次持有锁资源,唤醒线程)
-
返回
#include<iostream>
#include<thread>
#include<mutex>
#include<condition_variable>
using namespace std;
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void work_thread()//线程函数
{
cout<<"work_thread begin"<<endl;
std::unique_lock<std::mutex> lock(mtx);//mtx.lock,unique_lock不用自己释放锁资源。
while(!ready)//ready==false(主线程还没改read)//防止虚假唤醒
{
cout<<"ready == flase"<<endl;
cv.wait(lock);//没有锁(不持有资源)是不能用wait的
//wait等待被唤醒
}
cout<<"work_thread run"<<endl;
cout<<"work_thread end"<<endl;
}
int main()//主线程
{
std::thread tha(work_thread);
{
std::unique_lock<std::mutex> lock(mtx);
ready = true;
cout<<"main signals ready"<<endl;
}
tha.join();//阻塞等待线程返回
}
让三个线程分别运行A B C A B C的输出10次。
wait到条件变量队列,互斥锁释放。
条件变量队列:cv,被唤醒后放到mutex互斥队列中。
一个锁释放:互斥队列中的一个线程被唤醒到。必须获取锁才能从wait返回到就绪。
#include<iostream>
#include<thread>
#include<mutex>
#include<condition_variable>
using namespace std;
std::mutex mtx;
std::condition_variable cv;
const int n = 10;
int tag = 1;//1A,2B,3C,1A
void funa()
{
std::unique_lock<std::mutex> lock(mtx);
for (int i = 0; i < n; ++i)
{
while (tag != 1)
{
cv.wait(lock);
}
printf("funa: A \n");
tag = 2;
cv.notify_all();
}
}
void funb()
{
std::unique_lock<std::mutex> lock(mtx);
for (int i = 0; i < n; ++i)
{
while (tag != 2)
{
cv.wait(lock);
}
printf("funb: B \n");
tag = 3;
cv.notify_all();
}
}
void func()
{
std::unique_lock<std::mutex> lock(mtx);
for (int i = 0; i < n; ++i)
{
while (tag != 3)
{
cv.wait(lock);
}
printf("func: C \n");
tag = 1;
cv.notify_all();
}
}
int main()
{
std::thread tha(funa);
std::thread thb(funb);
std::thread thc(func);
tha.join();
thb.join();
thc.join();
return 0;
}