目录
std::lock_guard 的 std::adopt_lock 的参数
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;
my_mutex.lock();
msgRecvQueue.push_back(i);
my_mutex.unlock();
}
}
bool outMsgLULProc(int& command)
{
my_mutex.lock();
if (!msgRecvQueue.empty())
{
int command = msgRecvQueue.front();
msgRecvQueue.pop_front();
my_mutex.unlock();
return true;
}
my_mutex.unlock();
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_mutex;
};
int main()
{
A myobja;
thread myInMsgObj(&A::inMsgRecvQueue,&myobja);
thread myOutMsgObj(&A::outMsgRecvQueue,&myobja);
myInMsgObj.join();
myOutMsgObj.join();
cout << "main 主线程执行结束" << endl;
return 0;
}
上述代码是:lock() 和 unlock() 的版本,下面将其改为lock_guard 的版本,如下所示:
为了防止 unlock(),C++11 引入了 lock_guard,lock_guard直接取代 lock() 和 unlock()。
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;
//my_mutex.lock();
lock_guard<mutex> sbguard(my_mutex);
msgRecvQueue.push_back(i);
//my_mutex.unlock();
}
}
bool outMsgLULProc(int& command)
{
lock_guard<mutex> sbguard(my_mutex);
//my_mutex.lock();
if (!msgRecvQueue.empty())
{
int command = msgRecvQueue.front();
msgRecvQueue.pop_front();
//my_mutex.unlock();
return true;
}
//my_mutex.unlock();
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_mutex;
};
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,也可以和 lock() unlock()混用,不过不建议这样用,代码如下所示:
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
#include <set>
#include <string>
#include <stack>
#include <queue>
#include <thread>
using namespace std;
struct ListNode {
int val;
ListNode* next;
ListNode() : val(0), next(nullptr) {}
ListNode(int x) : val(x), next(nullptr) {}
ListNode(int x, ListNode* next) : val(x), next(next) {}
};
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode() : val(0), left(nullptr), right(nullptr) {}
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
TreeNode(int x, TreeNode* left, TreeNode* right) : val(x), left(left), right(right) {}
};
// 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;
//my_mutex.lock();
lock_guard<mutex> sbguard(my_mutex);
msgRecvQueue.push_back(i);
//my_mutex.unlock();
}
}
bool outMsgLULProc(int& command)
{
//lock_guard<mutex> sbguard(my_mutex);
my_mutex.lock();
if (!msgRecvQueue.empty())
{
int command = msgRecvQueue.front();
msgRecvQueue.pop_front();
my_mutex.unlock();
return true;
}
my_mutex.unlock();
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_mutex;
};
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 的代码也可以改为如下所示:
{
lock_guard<mutex> sbguard(my_mutex);
msgRecvQueue.push_back(i);
}
用 {} 将其括起来,{} 代表生命周期。这样可以提前结束sbguard的生命周期,让sbguard 提前unlock()。因为走出了 },sbguard 生命周期就会结束。
死锁演示
死锁一般的解决方案
死锁一般的解决方案:采用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;
my_mutex1.lock();
my_mutex2.lock();
//lock_guard<mutex> sbguard(my_mutex);
msgRecvQueue.push_back(i);
my_mutex1.unlock();
my_mutex2.unlock();
}
}
bool outMsgLULProc(int& command)
{
//lock_guard<mutex> sbguard(my_mutex);
my_mutex1.lock();
my_mutex2.lock();
if (!msgRecvQueue.empty())
{
int command = msgRecvQueue.front();
msgRecvQueue.pop_front();
my_mutex1.unlock();
my_mutex2.unlock();
return true;
}
my_mutex1.unlock();
my_mutex2.unlock();
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
// 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;
//my_mutex1.lock();
//my_mutex2.lock();
lock_guard<mutex> sbguard1(my_mutex1);
lock_guard<mutex> sbguard2(my_mutex2);
msgRecvQueue.push_back(i);
//my_mutex1.unlock();
//my_mutex2.unlock();
}
}
bool outMsgLULProc(int& command)
{
lock_guard<mutex> sbguard1(my_mutex1);
lock_guard<mutex> sbguard2(my_mutex2);
//my_mutex1.lock();
//my_mutex2.lock();
if (!msgRecvQueue.empty())
{
int command = msgRecvQueue.front();
msgRecvQueue.pop_front();
//my_mutex1.unlock();
//my_mutex2.unlock();
return true;
}
//my_mutex1.unlock();
//my_mutex2.unlock();
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::lock()
std::lock()函数模板,要处理多个互斥量才出场
用法示例:lock(my_mutex1,my_mutex2,....),后面必须调用unlock,unlock
能力->
1.一次锁住两个或者两个以上的互斥量(至少两个,多了不限,1个不行)
2.他不存在这种因为在多个线程中,因为锁的顺序问题导致死锁的风险问题。std::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;
//my_mutex1.lock();
//my_mutex2.lock();
//lock_guard<mutex> sbguard1(my_mutex1);
//lock_guard<mutex> sbguard2(my_mutex2);
lock(my_mutex1, my_mutex2);
msgRecvQueue.push_back(i);
my_mutex1.unlock();
my_mutex2.unlock();
}
}
bool outMsgLULProc(int& command)
{
//lock_guard<mutex> sbguard1(my_mutex1);
//lock_guard<mutex> sbguard2(my_mutex2);
//my_mutex1.lock();
//my_mutex2.lock();
lock(my_mutex1, my_mutex2);
if (!msgRecvQueue.empty())
{
int command = msgRecvQueue.front();
msgRecvQueue.pop_front();
my_mutex1.unlock();
my_mutex2.unlock();
return true;
}
my_mutex1.unlock();
my_mutex2.unlock();
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::lock_guard 的 std::adopt_lock 的参数
std::adopt_lock:是一个结构体对象,起一个标记作用:作用就是表示这个互斥量已经lock(),不需要在std::lock_guard<std::mutex>里面对mutex对象进行再次lock()了。
为什么要引入这个adopt_locak 的这个参数,因为在调用lock(my_mutex1,my_mutex2,...)的时候,后面还需要自己手动调用unlock,这个时候很容易忘记。
所以在lock(my_mutex1,my_mutex2)
......
后面可以用,
std::lock_guard<mutex> sbguard1(my_mutex1,std:;adopt_lock)
std::lock_guard<mutex> sbguard2(my_mutex2,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;
//my_mutex1.lock();
//my_mutex2.lock();
//lock_guard<mutex> sbguard1(my_mutex1);
//lock_guard<mutex> sbguard2(my_mutex2);
lock(my_mutex1, my_mutex2);
msgRecvQueue.push_back(i);
my_mutex1.unlock();
my_mutex2.unlock();
}
}
bool outMsgLULProc(int& command)
{
//lock_guard<mutex> sbguard1(my_mutex1);
//lock_guard<mutex> sbguard2(my_mutex2);
//my_mutex1.lock();
//my_mutex2.lock();
lock(my_mutex1, my_mutex2);
lock_guard<mutex> sbguard1(my_mutex1,std::adopt_lock);
lock_guard<mutex> sbguard2(my_mutex2,std::adopt_lock);
if (!msgRecvQueue.empty())
{
int command = msgRecvQueue.front();
msgRecvQueue.pop_front();
//my_mutex1.unlock();
//my_mutex2.unlock();
return true;
}
//my_mutex1.unlock();
//my_mutex2.unlock();
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::lock() 一次锁定多个互斥量,不太常用,建议一个一个锁。