C++并行开发6-unique_lock详解.md
一、 unique_lock 取代lock_guard
adopt_lock
表示这个互斥量已经被lock了,必须把互斥量提前lock,否则会报异常
try_to_lock
当outMsgRecgQueue线程有一个sleep的时候,会导致另一个inMsgRecvQueue线程卡死,尝试使用mutex的lock()
去锁定这个互斥量,但是如果没有锁定成功,也会立即返回,并不会阻塞在那里
#include <iostream>
#include <thread>
#include <algorithm>
#include <vector>
#include <list>
#include <mutex>
using namespace std;
//调用类对象的成员函数的方式来创建线程
class A {
public:
void inMsgRecvQueue()
{
for (int i = 0; i < 10000; i++) {
//std::lock_guard<std::mutex> sbguard1(my_mutex1); //前面已经锁过了,这里需要adopt_lock
/*std::unique_lock<std::mutex> sbguard1(my_mutex1);
cout << "消息队列插入一个元素 " << i << endl;
msgRecvQueue.push_back(i);*/
std::unique_lock<std::mutex> sbguard1(my_mutex1, std::try_to_lock); //尝试拿到锁头
if (sbguard1.owns_lock()) {
msgRecvQueue.push_back(i);
}
else {
cout << "inMsgRecvQueue 执行但是没有拿到锁头, 干点其他的事" << endl;
}
}
}
bool judgeOutMsg(int &command) {
//std::lock_guard<std::mutex> sbguard1(my_mutex1);
//将lock_guard 取代成unique_lock
std::unique_lock<std::mutex> sbguard1(my_mutex1);
std::chrono::milliseconds dura(20000); //20s
std::this_thread::sleep_for(dura); //休息20s 这个线程休息20s,导致下一个线程因为互斥量也休息了20s
if (!msgRecvQueue.empty()) {
//消息队列非空
command = msgRecvQueue.front(); //取出第一个元素
msgRecvQueue.pop_front();
return true;
}
else {
return false;
}
}
void outMsgRecgQueue() {
int commond = 0;
for (int i = 0; i < 10000; i++) {
bool result = judgeOutMsg(commond);
if (result) {
cout << "消息队列中取出了一个元素 " << commond << endl;
}
else {
cout << "消息队列为空 " << endl;
}
}
}
private:
list<int> msgRecvQueue; //消息队列
std::mutex my_mutex1;// 创建一个互斥量
std::mutex my_mutex2;// 创建一个互斥量
};
int main()
{
A myobja;
std::thread myOutnMsgObj(&A::outMsgRecgQueue, &myobja);
std::thread myInnMsgObj(&A::inMsgRecvQueue, &myobja);
//这里必须使用引用,否则线程会重新拷贝构造一个对象,
//但是使用引用就需要考虑类对象的使用周期,必须在主线程使用结束
myOutnMsgObj.join();
myInnMsgObj.join();
//一、 unique_lock 取代lock_guard
// unique_lock 是一个类模板, 比lock_guard灵活很多,但是内存,效率差一些
// 1.1 std::adopt_lock :表示这个互斥量已经被lock了,必须把互斥量提前lock,否则会报异常
// 1.2 std::try_to_lock
// 尝试使用mutex的lock() 去锁定这个互斥量,但是如果没有锁定成功,也会立即返回,并不会阻塞在那里
// 用这个try_to_lock的前提是自己不能去lock
return 0;
}
std::defer_lock
主要用于成员函数中
2. unique_lock的一些成员函数
2.1 lock() 加锁 && 2.2 unlock()
因为有一些非共享数据要处理,所有要处理一些非共享数据,因此可以人为的加lock或者unlock
#include <iostream>
#include <thread>
#include <algorithm>
#include <vector>
#include <list>
#include <mutex>
using namespace std;
//调用类对象的成员函数的方式来创建线程
class A {
public:
void inMsgRecvQueue()
{
for (int i = 0; i < 10000; i++) {
//std::lock_guard<std::mutex> sbguard1(my_mutex1); //前面已经锁过了,这里需要adopt_lock
/*std::unique_lock<std::mutex> sbguard1(my_mutex1);
cout << "消息队列插入一个元素 " << i << endl;
msgRecvQueue.push_back(i);*/
//std::unique_lock<std::mutex> sbguard1(my_mutex1, std::try_to_lock); //尝试拿到锁头
//if (sbguard1.owns_lock()) {
// msgRecvQueue.push_back(i);
//}
//else {
// cout << "inMsgRecvQueue 执行但是没有拿到锁头, 干点其他的事" << endl;
//}
std::unique_lock<std::mutex> sbguard1(my_mutex1, std::defer_lock);
sbguard1.lock(); //不用担心解锁,这里会自动解锁
msgRecvQueue.push_back(i);
}
}
bool judgeOutMsg(int &command) {
//std::lock_guard<std::mutex> sbguard1(my_mutex1);
//将lock_guard 取代成unique_lock
std::unique_lock<std::mutex> sbguard1(my_mutex1);
//std::chrono::milliseconds dura(20000); //20s
//std::this_thread::sleep_for(dura); //休息20s 这个线程休息20s,导致下一个线程因为互斥量也休息了20s
if (!msgRecvQueue.empty()) {
//消息队列非空
command = msgRecvQueue.front(); //取出第一个元素
msgRecvQueue.pop_front();
return true;
}
else {
return false;
}
}
void outMsgRecgQueue() {
int commond = 0;
for (int i = 0; i < 10000; i++) {
bool result = judgeOutMsg(commond);
if (result) {
cout << "消息队列中取出了一个元素 " << commond << endl;
}
else {
cout << "消息队列为空 " << endl;
}
}
}
private:
list<int> msgRecvQueue; //消息队列
std::mutex my_mutex1;// 创建一个互斥量
std::mutex my_mutex2;// 创建一个互斥量
};
int main()
{
A myobja;
std::thread myOutnMsgObj(&A::outMsgRecgQueue, &myobja);
std::thread myInnMsgObj(&A::inMsgRecvQueue, &myobja);
//这里必须使用引用,否则线程会重新拷贝构造一个对象,
//但是使用引用就需要考虑类对象的使用周期,必须在主线程使用结束
myOutnMsgObj.join();
myInnMsgObj.join();
//一、 unique_lock 取代lock_guard
// unique_lock 是一个类模板, 比lock_guard灵活很多,但是内存,效率差一些
// 1.1 std::adopt_lock :表示这个互斥量已经被lock了,必须把互斥量提前lock,否则会报异常
// 1.2 std::try_to_lock
// 尝试使用mutex的lock() 去锁定这个互斥量,但是如果没有锁定成功,也会立即返回,并不会阻塞在那里
// 用这个try_to_lock的前提是自己不能去lock
// 1.3 std::defer_lock
// 用这个defer_lock的前提是你自己不能先lock,否则会报异常
// defer_lock的意思是并没有给mutex加锁,初始化了一个没有加锁的mutex
// 2. unique_lock的一些成员函数
// 2.1 lock() 加锁
// 2.2 unlock() 因为有一些非共享数据要处理,所有要处理一些非共享数据
return 0;
}
try_lock()
尝试给互斥量加锁,如果拿不到锁,则返回false,如果拿到锁,返回true,这个函数不堵塞,类似try_to_lock
void inMsgRecvQueue()
{
for (int i = 0; i < 10000; i++) {
//std::lock_guard<std::mutex> sbguard1(my_mutex1); //前面已经锁过了,这里需要adopt_lock
/*std::unique_lock<std::mutex> sbguard1(my_mutex1);
cout << "消息队列插入一个元素 " << i << endl;
msgRecvQueue.push_back(i);*/
//std::unique_lock<std::mutex> sbguard1(my_mutex1, std::try_to_lock); //尝试拿到锁头
//if (sbguard1.owns_lock()) {
// msgRecvQueue.push_back(i);
//}
//else {
// cout << "inMsgRecvQueue 执行但是没有拿到锁头, 干点其他的事" << endl;
//}
std::unique_lock<std::mutex> sbguard1(my_mutex1, std::defer_lock);
//sbguard1.lock(); //不用担心解锁,这里会自动解锁
if (sbguard1.try_lock()) {
msgRecvQueue.push_back(i);
}
else {
cout << "inMsgRecvQueue 执行但是没有拿到锁头, 干点其他的事" << endl;
}
}
}
release函数
锁住代码的多少称为锁头的粒度
void inMsgRecvQueue()
{
for (int i = 0; i < 10000; i++) {
std::unique_lock<std::mutex> sbguard1(my_mutex1);
std::mutex *ptx = sbguard1.release(); //可以接管mutex
//ptx->lock(); //这里不能再lock 了因为前面已经lock 过了
msgRecvQueue.push_back(i);
ptx->unlock();
}
}
unique_lock所有权的传递
使用移动构造函数可以使所有权进行转移
std::unique_lock<std::mutex> sbguard1(my_mutex1);
std::unique_lock<std::mutex> sbguard2(std::move(sbguard1)); //使用移动构造函数 sbguard2 和 my_mutex1绑定一起了,sbguard1指向空
也可以写一个类中的函数进行所有权转移 F:/网站备份-20221127/zhouaq_backup_20221127.com/zhouaq.com/wp-content/p://zhouaq.com/wp-./uploads/2020/10/wp_editor_md_e554cff01d898b6df220102aa7c84b22.jpg)](http://zhouaq.com/wp-
content/uploads/2020/10/wp_editor_md_e554cff01d898b6df220102aa7c84b22.jpg)
- Title: C++并行开发6-unique_lock详解.md
- Author: FengLY
- Created at : 2023-06-18 22:40:09
- Updated at : 2023-06-18 22:57:07
- Link: https://zhouaq.com/2023/06/18/C++并行开发6-unique_lock详解/
- License: This work is licensed under CC BY-NC-SA 4.0.
Comments