背景
(1) unique_lock 取代lock_guard
(2)unique_lock的第二个参数
2.1.std::adopt_lock
2.2 std::try_to_lock
2.3 std::defer_lock
(3) unique_lock的成员函数
3.1 lock
3.2 unlock()
3.3 try_lock()
3.4 release()
(4) unique_lock 所有权的传递
unique_lock 取代lock_guard
unique_lock 是一个类模板,工作中,一般使用lock_guard(推荐使用);lock_guard取代了mutex的lock() 和 unlock() 的函数。
unique_lock比lock_guard灵活了很多;效率上差一点,内存上多一点。
// test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
#include <iostream>
#include <string>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <list>
#include <thread>
#include <chrono>
#include <mutex>
using namespace std;
class A
{
public:
void inMsgRecvQueue()
{
for (int i = 0; i < 100000; i++)
{
cout << "inMsgRecvQueue 线程执行,插入一个元素:" << i << endl;
//lock_guard<mutex> sbguard1(my_mutex1);
//lock_guard<mutex> sbguard2(my_mutex2);
unique_lock<mutex> sbguard1(my_mutex1);
unique_lock<mutex> sbguard2(my_mutex2);
msgRecvQueue.push_back(i);
}
}
bool outMsgLULProc(int& command)
{
//lock_guard<mutex> sbguard1(my_mutex1);
//lock_guard<mutex> sbguard2(my_mutex2);
unique_lock<mutex> sbguard1(my_mutex1);
unique_lock<mutex> sbguard2(my_mutex2);
if (!msgRecvQueue.empty())
{
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
return true;
}
return false;
}
void outMsgRecvQueue()
{
int command = 0;
for (int i = 0; i < 100000; i++)
{
bool result = outMsgLULProc(command);
if (result == true)
{
cout << "outMsgRecvQueue(),执行了,从容器中取出一个元素:" << command << endl;
}
else
{
cout << "outMsgRecvQueue 线程执行了,但是目前消息队列中的元素是为空:" << i << endl;
}
}
}
private:
list<int> msgRecvQueue;
mutex my_mutex1;
mutex my_mutex2;
};
int main()
{
A myobja;
thread myInMsgObj(&A::inMsgRecvQueue,&myobja);
thread myOutMsgObj(&A::outMsgRecvQueue,&myobja);
myInMsgObj.join();
myOutMsgObj.join();
cout << "main 主线程执行结束" << endl;
return 0;
}
lock_guard的第二个参数
adopt_lock标记作用;表示这个互斥量已经被lock了,(你必须要把互斥量提前lock,否者会报异常)
adopt_lock标记的效果就是:假设调用方线程已经拥有了互斥的所有权(已经lock()成功了),通知lock_guard不需要在构造函数中lock这个互斥量了。
unique_lock也可以带std::adopt_lock
my_mutex1.lock()
std::unique_lock<std::mutex> sbguard1(my_mutex1,std::adopt_lock)
// test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
#include <iostream>
#include <string>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <list>
#include <thread>
#include <chrono>
#include <mutex>
using namespace std;
class A
{
public:
void inMsgRecvQueue()
{
for (int i = 0; i < 100000; i++)
{
cout << "inMsgRecvQueue 线程执行,插入一个元素:" << i << endl;
//lock_guard<mutex> sbguard1(my_mutex1);
//lock_guard<mutex> sbguard2(my_mutex2);
my_mutex1.lock();
unique_lock<mutex> sbguard1(my_mutex1,std::adopt_lock);
unique_lock<mutex> sbguard2(my_mutex2);
msgRecvQueue.push_back(i);
}
}
bool outMsgLULProc(int& command)
{
//lock_guard<mutex> sbguard1(my_mutex1);
//lock_guard<mutex> sbguard2(my_mutex2);
unique_lock<mutex> sbguard1(my_mutex1);
unique_lock<mutex> sbguard2(my_mutex2);
if (!msgRecvQueue.empty())
{
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
return true;
}
return false;
}
void outMsgRecvQueue()
{
int command = 0;
for (int i = 0; i < 100000; i++)
{
bool result = outMsgLULProc(command);
if (result == true)
{
cout << "outMsgRecvQueue(),执行了,从容器中取出一个元素:" << command << endl;
}
else
{
cout << "outMsgRecvQueue 线程执行了,但是目前消息队列中的元素是为空:" << i << endl;
}
}
}
private:
list<int> msgRecvQueue;
mutex my_mutex1;
mutex my_mutex2;
};
int main()
{
A myobja;
thread myInMsgObj(&A::inMsgRecvQueue,&myobja);
thread myOutMsgObj(&A::outMsgRecvQueue,&myobja);
myInMsgObj.join();
myOutMsgObj.join();
cout << "main 主线程执行结束" << endl;
return 0;
}
std::try_to_lock
// test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
#include <iostream>
#include <string>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <list>
#include <thread>
#include <chrono>
#include <mutex>
using namespace std;
class A
{
public:
void inMsgRecvQueue()
{
for (int i = 0; i < 100000; i++)
{
cout << "inMsgRecvQueue 线程执行,插入一个元素:" << i << endl;
//lock_guard<mutex> sbguard1(my_mutex1);
//lock_guard<mutex> sbguard2(my_mutex2);
unique_lock<mutex> sbguard1(my_mutex1,std::try_to_lock);
if (sbguard1.owns_lock())
{
}
else
{
cout << "没有拿到锁,只能做点别的事情:" << i << endl;
}
unique_lock<mutex> sbguard2(my_mutex2,std::try_to_lock);
if (sbguard2.owns_lock())
{
msgRecvQueue.push_back(i);
}
else
{
cout << "没有拿到锁,只能做点别的事情:" << i << endl;
}
}
}
bool outMsgLULProc(int& command)
{
//lock_guard<mutex> sbguard1(my_mutex1);
//lock_guard<mutex> sbguard2(my_mutex2);
unique_lock<mutex> sbguard1(my_mutex1);
unique_lock<mutex> sbguard2(my_mutex2);
std::chrono::milliseconds dura(20000); //1秒 = 1000毫秒,所以20000毫秒 = 20秒
std::this_thread::sleep_for(dura); //休息一定的时长
if (!msgRecvQueue.empty())
{
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
return true;
}
return false;
}
void outMsgRecvQueue()
{
int command = 0;
for (int i = 0; i < 100000; i++)
{
bool result = outMsgLULProc(command);
if (result == true)
{
cout << "outMsgRecvQueue(),执行了,从容器中取出一个元素:" << command << endl;
}
else
{
cout << "outMsgRecvQueue 线程执行了,但是目前消息队列中的元素是为空:" << i << endl;
}
}
}
private:
list<int> msgRecvQueue;
mutex my_mutex1;
mutex my_mutex2;
};
int main()
{
A myobja;
thread myOutMsgObj(&A::outMsgRecvQueue, &myobja);
thread myInMsgObj(&A::inMsgRecvQueue,&myobja);
myInMsgObj.join();
myOutMsgObj.join();
cout << "main 主线程执行结束" << endl;
return 0;
}
std::defer_lock
unique_lock 所支持的另一个参数是:std::defer_lock(用这个defer_lock 的前提是程序员不能自己先去lock 这个mutex,否者会报异常,这点和try_to_lock一样的)
defer_lock的意思就是 并没有给mutex加锁,来介绍一下unique_lock的重要成员函数。
1.unique_lock 的成员函数 lock
// test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
#include <iostream>
#include <string>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <list>
#include <thread>
#include <chrono>
#include <mutex>
using namespace std;
class A
{
public:
void inMsgRecvQueue()
{
for (int i = 0; i < 100000; i++)
{
cout << "inMsgRecvQueue 线程执行,插入一个元素:" << i << endl;
std::unique_lock<std::mutex> sbguard1(my_mutex1,std::defer_lock); //没有加锁的my_mutex1
sbguard1.lock(); //不能自己unlock,unique_lock 会自己unlock
std::unique_lock<std::mutex> sbguard2(my_mutex2, std::defer_lock); //没有加锁的my_mutex2
sbguard2.lock();//不能自己unlock,unique_lock 会自己unlock
msgRecvQueue.push_back(i);
}
}
bool outMsgLULProc(int& command)
{
//lock_guard<mutex> sbguard1(my_mutex1);
//lock_guard<mutex> sbguard2(my_mutex2);
unique_lock<mutex> sbguard1(my_mutex1);
unique_lock<mutex> sbguard2(my_mutex2);
std::chrono::milliseconds dura(20000); //1秒 = 1000毫秒,所以20000毫秒 = 20秒
std::this_thread::sleep_for(dura); //休息一定的时长
if (!msgRecvQueue.empty())
{
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
return true;
}
return false;
}
void outMsgRecvQueue()
{
int command = 0;
for (int i = 0; i < 100000; i++)
{
bool result = outMsgLULProc(command);
if (result == true)
{
cout << "outMsgRecvQueue(),执行了,从容器中取出一个元素:" << command << endl;
}
else
{
cout << "outMsgRecvQueue 线程执行了,但是目前消息队列中的元素是为空:" << i << endl;
}
}
}
private:
list<int> msgRecvQueue;
mutex my_mutex1;
mutex my_mutex2;
};
int main()
{
A myobja;
thread myOutMsgObj(&A::outMsgRecvQueue, &myobja);
thread myInMsgObj(&A::inMsgRecvQueue,&myobja);
myInMsgObj.join();
myOutMsgObj.join();
cout << "main 主线程执行结束" << endl;
return 0;
}
unique_lock 的成员函数 unlock
引入unique_lock 的成员函数 unlock,目的就是:因为有一些非共享代码需要处理,咋们不希望一直被lock住,当共享代码处理完了之后,就立马unlock。
// test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
#include <iostream>
#include <string>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <list>
#include <thread>
#include <chrono>
#include <mutex>
using namespace std;
class A
{
public:
void inMsgRecvQueue()
{
for (int i = 0; i < 100000; i++)
{
cout << "inMsgRecvQueue 线程执行,插入一个元素:" << i << endl;
std::unique_lock<std::mutex> sbguard1(my_mutex1,std::defer_lock); //没有加锁的my_mutex1
sbguard1.lock(); //不能自己unlock,unique_lock 会自己unlock
std::unique_lock<std::mutex> sbguard2(my_mutex2, std::defer_lock); //没有加锁的my_mutex2
sbguard2.lock();//不能自己unlock,unique_lock 会自己unlock
//处理一些非共享代码
//..........
//.........
sbguard2.unlock();
sbguard2.lock();
msgRecvQueue.push_back(i);
sbguard2.unlock(); //画蛇添足,也可以
}
}
bool outMsgLULProc(int& command)
{
//lock_guard<mutex> sbguard1(my_mutex1);
//lock_guard<mutex> sbguard2(my_mutex2);
unique_lock<mutex> sbguard1(my_mutex1);
unique_lock<mutex> sbguard2(my_mutex2);
//std::chrono::milliseconds dura(20000); //1秒 = 1000毫秒,所以20000毫秒 = 20秒
//std::this_thread::sleep_for(dura); //休息一定的时长
if (!msgRecvQueue.empty())
{
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
return true;
}
return false;
}
void outMsgRecvQueue()
{
int command = 0;
for (int i = 0; i < 100000; i++)
{
bool result = outMsgLULProc(command);
if (result == true)
{
cout << "outMsgRecvQueue(),执行了,从容器中取出一个元素:" << command << endl;
}
else
{
cout << "outMsgRecvQueue 线程执行了,但是目前消息队列中的元素是为空:" << i << endl;
}
}
}
private:
list<int> msgRecvQueue;
mutex my_mutex1;
mutex my_mutex2;
};
int main()
{
A myobja;
thread myOutMsgObj(&A::outMsgRecvQueue, &myobja);
thread myInMsgObj(&A::inMsgRecvQueue,&myobja);
myInMsgObj.join();
myOutMsgObj.join();
cout << "main 主线程执行结束" << endl;
return 0;
}
std::try_lock
3.3 try_lock(),尝试给互斥量加锁,如果拿不到锁,则返回false,如果拿到了锁,返回true,这个函数是不阻塞的。
// test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
#include <iostream>
#include <string>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <list>
#include <thread>
#include <chrono>
#include <mutex>
using namespace std;
class A
{
public:
void inMsgRecvQueue()
{
for (int i = 0; i < 100000; i++)
{
cout << "inMsgRecvQueue 线程执行,插入一个元素:" << i << endl;
std::unique_lock<std::mutex> sbguard1(my_mutex1,std::defer_lock); //没有加锁的my_mutex1
sbguard1.lock(); //不能自己unlock,unique_lock 会自己unlock
std::unique_lock<std::mutex> sbguard2(my_mutex2, std::defer_lock); //没有加锁的my_mutex2
if (sbguard2.try_lock() == true)
{
msgRecvQueue.push_back(i);
}
else
{
cout << "inMsgRecvQueue() 线程没有拿到锁,只能干点别的事:" << i << endl;
}
}
}
bool outMsgLULProc(int& command)
{
//lock_guard<mutex> sbguard1(my_mutex1);
//lock_guard<mutex> sbguard2(my_mutex2);
unique_lock<mutex> sbguard1(my_mutex1);
unique_lock<mutex> sbguard2(my_mutex2);
//std::chrono::milliseconds dura(20000); //1秒 = 1000毫秒,所以20000毫秒 = 20秒
//std::this_thread::sleep_for(dura); //休息一定的时长
if (!msgRecvQueue.empty())
{
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
return true;
}
return false;
}
void outMsgRecvQueue()
{
int command = 0;
for (int i = 0; i < 100000; i++)
{
bool result = outMsgLULProc(command);
if (result == true)
{
cout << "outMsgRecvQueue(),执行了,从容器中取出一个元素:" << command << endl;
}
else
{
cout << "outMsgRecvQueue 线程执行了,但是目前消息队列中的元素是为空:" << i << endl;
}
}
}
private:
list<int> msgRecvQueue;
mutex my_mutex1;
mutex my_mutex2;
};
int main()
{
A myobja;
thread myOutMsgObj(&A::outMsgRecvQueue, &myobja);
thread myInMsgObj(&A::inMsgRecvQueue,&myobja);
myInMsgObj.join();
myOutMsgObj.join();
cout << "main 主线程执行结束" << endl;
return 0;
}
release
4.release() 返回它所管理的mutex对象指针,并释放所有权;也就是说,这个unique_lock 和 mutex不再有关系。
//严格区分unlock()和release()的区别,不要混淆。
//如果原来mutex对象处于加锁状态,你有责任接管过来并负责解锁。(release返回的是原始mutex的指针)
// test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
#include <iostream>
#include <string>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <list>
#include <thread>
#include <chrono>
#include <mutex>
using namespace std;
class A
{
public:
void inMsgRecvQueue()
{
for (int i = 0; i < 100000; i++)
{
cout << "inMsgRecvQueue 线程执行,插入一个元素:" << i << endl;
std::unique_lock<std::mutex> sbguard1(my_mutex1);
std::mutex* ptx = sbguard1.release();
ptx->unlock();
std::unique_lock<std::mutex> sbguard2(my_mutex2, std::defer_lock); //没有加锁的my_mutex2
if (sbguard2.try_lock() == true)
{
msgRecvQueue.push_back(i);
}
else
{
cout << "inMsgRecvQueue() 线程没有拿到锁,只能干点别的事:" << i << endl;
}
}
}
bool outMsgLULProc(int& command)
{
//lock_guard<mutex> sbguard1(my_mutex1);
//lock_guard<mutex> sbguard2(my_mutex2);
unique_lock<mutex> sbguard1(my_mutex1);
unique_lock<mutex> sbguard2(my_mutex2);
//std::chrono::milliseconds dura(20000); //1秒 = 1000毫秒,所以20000毫秒 = 20秒
//std::this_thread::sleep_for(dura); //休息一定的时长
if (!msgRecvQueue.empty())
{
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
return true;
}
return false;
}
void outMsgRecvQueue()
{
int command = 0;
for (int i = 0; i < 100000; i++)
{
bool result = outMsgLULProc(command);
if (result == true)
{
cout << "outMsgRecvQueue(),执行了,从容器中取出一个元素:" << command << endl;
}
else
{
cout << "outMsgRecvQueue 线程执行了,但是目前消息队列中的元素是为空:" << i << endl;
}
}
}
private:
list<int> msgRecvQueue;
mutex my_mutex1;
mutex my_mutex2;
};
int main()
{
A myobja;
thread myOutMsgObj(&A::outMsgRecvQueue, &myobja);
thread myInMsgObj(&A::inMsgRecvQueue,&myobja);
myInMsgObj.join();
myOutMsgObj.join();
cout << "main 主线程执行结束" << endl;
return 0;
}
unique_lock 所有权的传递(转移)
4.unique_lock 所有权的传递(转移)
一般有2种方法
1.std::move(...)
2.return unique_lock对象