第五节 互斥量概念、用法、死锁演示及解决详解
(1)互斥量(mutex)的基本概念
(2)互斥量的用法
(2.1)lock(),unlock()
(2.2)std::lock_guard类模板
(3)死锁
(3.1)死锁演示
(3.2)死锁的一般解决方案
(3.3)std::lock()函数模板
(3.4)std::lock_guard的std::adopt_lock参数
第六节 unique_lock详解
(1)unique_lock取代lock_guard
unique_lock是一个类模板,工作中一般推荐使用lock_guard;lock_guard取代了mutex的lock()和unlock()
unique_lock比lock_guard灵活很多;效率上差一点,内存占用多一点。
std::lock_guard<std::mutex> sbguard1(my_mutex1, std::adopt_lock); // adopt_lock起一个标记作用
(2)unique_lock的第二个参数
(2.1)std::adopt_lock
std::lock_guard<std::mutex> sbguard1(my_mutex1, std::adopt_lock); // adopt_lock起一个标记作用
adopt_lock标记的效果就是“假设调用方”线程已经拥有了互斥的所有权(已经lock()成功了)。
表示这个互斥量已经被lock了(你必须要把互斥量提前lock,否则回报异常),通知lock_guard不需要在构造函数中lock这个互斥量了;
unique_lock的参数含义相同。
(2.2)std::try_to_lock
我们会尝试用mutex的lock()去锁定这个mutex,但是如果没有锁定成功,也会立即返回,并不会阻塞;
用这个的前提是自己不能先去lock(),否则会双重锁定。
(2.3)std::defer_lock
用这个的前提是自己不能先去lock();
defer_lock并没有给mutex加锁;初始化了一个没有加锁的mutex
(3)unique_lock的成员函数
(3.1)lock()
(3.2)unlock()
(3.3)try_lock()
(3.4)release()
返回它所管理的mutex对象指针,并释放所有权;也就是说,这个unique_lock和mutex不再有联系。
严格区分unlock()和release()
sbguard1 = {_Pmtx=0x010ffd3c {...} _Owns=true }
+ &my_mutex1 0x010ffd3c {...} std::mutex *
(4)unique_lock所有权的传递
#include <iostream>
#include <thread>
#include <windows.h>
#include <string>
#include <vector>
#include <list>
#include <mutex>
using namespace std;
class A {
public:
void inMsgRecvQueue()
{
for (int i = 0; i < 1000; ++i)
{
cout << "inMsgRecvQueue()执行,插入一个元素" << i << endl;
{
//6.1
//std::lock_guard<std::mutex> sbguard(my_mutex1);
//std::unique_lock<std::mutex> sbguard(my_mutex1);
//6.2.1
//my_mutex1.lock();
//std::unique_lock<std::mutex> sbguard1(my_mutex1, std::adopt_lock);
//6.2.2
/*std::unique_lock<std::mutex> sbguard1(my_mutex1, std::try_to_lock);
if (sbguard1.owns_lock())
{
msgRecvQueue.push_back(i);
}
else
{
cout << "inMsgRecvQueue()执行,没拿到锁。" << endl;
}*/
//6.2.3
//std::unique_lock<std::mutex> sbguard1(my_mutex1, std::defer_lock); // 没有加锁的my_mutex1
//sbguard1.lock();
//6.3.3
/*if (sbguard1.try_lock() == true)
{
msgRecvQueue.push_back(i);
}
else
{
cout << "inMsgRecvQueue()执行,没拿到锁。" << endl;
}*/
// 6.3.4
std::unique_lock<std::mutex> sbguard1(my_mutex1);
std::mutex *ptx = sbguard1.release(); //
msgRecvQueue.push_back(i);
ptx->unlock();
// 6.4
std::unique_lock<std::mutex> sbguard1(my_mutex1);
std::unique_lock<std::mutex> sbguard2(std::move(sbguard1));
msgRecvQueue.push_back(i);
}
} // end for
}
bool outMsgLULProc(int &command)
{
//std::lock_guard<std::mutex> sbguard(my_mutex1);
//std::lock_guard<std::mutex> sbguard(my_mutex1);
std::unique_lock<std::mutex> sbguard(my_mutex1);
//my_mutex2.lock(); // 死锁
//my_mutex1.lock();
//my_mutex2.lock();
std::chrono::milliseconds dura(10);
std::this_thread::sleep_for(dura);
//Sleep(20000);
if (!msgRecvQueue.empty())
{
command = msgRecvQueue.front();
msgRecvQueue.pop_front(); // 移除第一个元素
//my_mutex1.unlock();
//my_mutex2.unlock();
return true;
}
//my_mutex2.unlock();
//my_mutex1.unlock();
return false;
}
void outMsgRecvQueue()
{
int command = 0;
for (int i = 0; i < 1000; ++i)
{
bool result = outMsgLULProc(command);
if (result == true)
{
cout << "outMsgRecvQueue()执行,移除第一个元素" << endl;
}
else
{
cout << "outMsgRecvQueue()执行,但目前消息队列中为空" << i << endl;
}
}
cout << " end " << endl;
}
private:
std::list<int> msgRecvQueue;
std::mutex my_mutex1;
std::mutex my_mutex2;
};
int main()
{
// 一、创建和等待多个线程
//vector<thread> mythreads;
//for (int i = 0; i < 10; ++i)
//{
// mythreads.push_back(std::thread(myPrint, i)); // 创建并开始执行
//}
//for (auto iter = mythreads.begin(); iter != mythreads.end(); ++iter)
//{
// iter->join();
//}
// 数据共享问题分析
// 有读有写
// 三、共享数据的保护案例代码
A myobja;
std::thread myOutMsgObj(&A::outMsgRecvQueue, std::ref(myobja));
std::thread myInMsgObj(&A::inMsgRecvQueue, std::ref(myobja));
myOutMsgObj.join();
myInMsgObj.join();
return 0;
}