demo代码混乱仅供参考
普通的lock和unlock运用
互斥锁种类
互斥锁:mutex
带有超时机制的互斥锁:timed_mutex
递归互斥锁:recursive_mutex
带有超时机制的递归互:recursive_timed_mutex
mutex
加锁的理由如下图
【确保同一时间只有一个线程访问共享资源】
【访问共享资源前加锁,使用后解锁】
void fun(int ret) {
flag.lock();
cout << "我是" << ret << "号,我来上厕所了,我把门关上了" << endl;
Sleep(1000);
cout << "我是" << ret << "号,我上完了,我把门打开了,有请下一位" << endl;
Sleep(500);
flag.unlock();
}
recursive_mutex递归互斥锁[重要]
mutex无法解决已经加锁的情况下下一个函数又要用这个互斥量(又要加锁)的问题,如下图
所以引入递归互斥锁(recursive_mutex)解决这个问题
timed_mutex超时机制互斥锁
一个线程被堵塞过久可以先执行
demo 之lock、unlock
lock和unlock成对出现> if前用lock,则再if和else处各用一次unlock
#include <iostream>
using namespace std;
#include <thread>
#include <list>
#include <vector>
#include <mutex>//
//只读的数据不用加锁
//有独有写药用用mutex【不能同时读,不能同时写,a写bcd都不能读】
vector <int> ret(10, 1);//全局数据【共享数据】
//线程入口函数
void show(int val) {
cout << "show--->" << val << endl;
cout << "线程ID:" << this_thread::get_id() << endl << ret[0] << ret[1] << ret[2] << endl;
}
//
class stu {
public:
//lock和unlock是成对出现
void inque() {
for (int i = 0; i < 10000; i++) {
cout << "inque函数(),插入一个元素" << i << endl;
signal.lock();
myque.push_back(i);
signal.unlock();
}
}
bool outsuo(int& com) {
signal.lock();
if (!myque.empty()) {
int com = myque.front();
myque.pop_front();
signal.unlock();
return 1;
}
signal.unlock();
return 0;
}
void outque() {
int com = 0;
for (int i = 0; i < 10000; i++) {
bool res = outsuo(com);
if (res) {
cout<<"outque函数,去除元素"<<com<<endl;
}
else {
cout << "outque函数()消息队列为空:" << i << endl;
}
}
}
private:
list <int> myque;
mutex signal;//创建互斥量成员变量
};
void test01();//创建多个线程
void test02();
int main() {
//test01();
test02();
}
void test02() {
stu s1;
thread myin(&stu::inque, &s1);//用引用保证同一个对象
thread myout(&stu::outque, &s1);
myin.join();
myout.join();
}
void test01() {
list <thread> myth;
for (int i = 0; i < 10; i++)
//多个线程运行顺序是乱的
myth.push_back(thread(show, i));//创建线程并已经开始执行[上下文切换]
for (auto it = myth.begin(); it != myth.end(); it++) {
//it->detach();
it->join();
}
}
lock_guard 替代lock和unlock
lock_guard 替代lock和unlock,之后lock、unlock不得再出现
格式
std::lock_guard <std::mutex> lock_guard_name(signal);
void fun(int ret) {
lock_guard <mutex> name(flag);
cout << "我是" << ret << "号,我来上厕所了,我把门关上了" << endl;
Sleep(1000);
cout << "我是" << ret << "号,我上完了,我把门打开了,有请下一位" << endl;
Sleep(500);
}
demo 之 lock_guard
void inque() {
for (int i = 0; i < 10000; i++) {
cout << "inque函数(),插入一个元素" << i << endl;
{//用大括号可以提前结束lock_guard
lock_guard <mutex>lock_guard_name(signal);
//lock_guard在析构时才解锁
myque.push_back(i);
}
//signal.unlock();
}
}
bool outsuo(int& com) {
//signal.lock();
lock_guard <mutex>lock_guard_name(signal);
if (!myque.empty()) {
com = myque.front();
myque.pop_front();
//signal.unlock();
return 1;
}
//signal.unlock();
return 0;
}
void outque() {
int com = 0;
for (int i = 0; i < 10000; i++) {
bool res = outsuo(com);
if (res) {
cout<<"outque函数,去除元素"<<com<<endl;
}
else {
cout << "outque函数()消息队列为空:" << i << endl;
}
}
}
死锁(至少两个互斥量)
死锁—>至少有两个互斥量
【两个互斥量上锁顺序一致不会死锁】
锁的代码少,则粒度细,运行效率高
🔒的代码多,则粒度粗,运行效率低
【只🔒与共享数据有关的数据】
案例(上锁顺序不一致,进入阻塞态)
解决方法
加锁顺序一致
(不展示)
运用lock同时锁两个互斥量
lock(signal,signal1);//同时上锁两个或多个,且不互锁
//注意解锁没有unlock两个参数,要分开写
signal.unlock();
signal1.ulock();
格式
lock(signal1,signal);//同时锁比较少用
//lock_guard用adopt_lock要一个一个写
lock+lock_guard可以不用unlock
//使用adopt_lock[可选择lock时要先lock,可以不再unlock]
lock(signal1,signal);
lock_guard <mutex> guard_name(signal,adopt_lock);
lock_guard <mutex>gard_name_1(signal1,adopt_lock);
unique_lock
unique_lock取代lock_gurad
[格式同lock_guard]
也可以
unique_lock < mutex> uni_name(signal);
【lock之后才可以adopt_lock】
用try _to_lock代替adopt_lock
此处不能先lock信号量
否则会锁两次
unique_lock <mutex> guard_name(signal, try_to_lock);
defer_lock [不能先lock,初始化没加🔒的mutex]
defer_lock表示目前不加锁,之后可能加锁,在使用unique_lock的lock方法时会检查当前是否拥有锁,如果拥有就会报错
unique_lock <mutex> guard_name(signal, defer_lock);
unique_lock成员函数
[unique_lock的lock和unlock不必一一对应,但是不可在unique_lock之上lock]
【但可以一一对应,也可不一一对应】
lock
unlock
try_lock[尝试给互斥量加🔒]
relesae
release[指针][把unique_lock和mutex之间的关系断开]
释放后,👨💻有义务自己unlock
bool outsuo(int& com) {
unique_lock<mutex>uni_name(signal);
mutex *ptr = uni_name.release();//释放后,👨💻有义务自己unlock
chrono::milliseconds dura(200);
this_thread::sleep_for(dura);
if (!myque.empty()) {
com = myque.front();
myque.pop_front();
ptr->unlock();//释放后,👨💻有义务自己unlock
return 1;
}
ptr->unlock();//释放后,👨💻有义务自己unlock
return 0;
}
转移所有权也可以实现release
unique_lock <mutex> guard_name(signal, try_to_lock);
//转移所有权[move移动语义]
//guard_name1与signal绑定,guard_name已经解除关系
unique_lock<mutex>guard_name1(move(guard_name));