1、互斥量时一个类对象,形象的理解时一把锁,多个线程尝试用lock()成员函数加锁,只有一个线程可以锁成功,如果没有锁成功会不断的尝试去获取锁。
互斥量使用的时候要小心,多了影响效率,少了起不到全面的保护效果。
方法:调用lock unlock 必须成对出现
#include <thread>
#include <iostream>
#include <vector>
#include <list>
#include <Windows.h>
#include <mutex>
using namespace std;
class RecvQueue {
public:
void inMsgRecvQueue() {
for (int i = 0; i < 100000; ++i) {
cout << "inMsgRecvQueue() start, push back one element: " << i << endl;
my_mutex.lock();
msgRecvQueue.push_back(i);
my_mutex.unlock();
}
}
bool outMsgLULProc(int &command) {
my_mutex.lock();
if (!msgRecvQueue.empty()) {
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
my_mutex.unlock();
return true;
}
my_mutex.unlock();
return false;
}
void outMsgRecvQueue() {
for (int i = 0; i < 100000; ++i) {
int command = 0;
bool result = outMsgLULProc(command);
if (result){
cout << "outMsgRecvQueue is start, pop one element:" << command << endl;
}
else {
cout << "outMsgRecvQueue is empty!" << endl;
}
}
}
private:
std::list<int> msgRecvQueue;
mutex my_mutex;
};
void main() {
RecvQueue myobj;
thread myoutqueue(&RecvQueue::outMsgRecvQueue, &myobj);
thread myinqueue(&RecvQueue::inMsgRecvQueue, &myobj);
myoutqueue.join();
myinqueue.join();
}
补充:
lock unlock可以两个函数可以通过lock_guard类模板直接取代。
2、死锁
产生条件:至少两个及以上的锁才有可能产生。
死锁的一般解决方案:
1)保证多个互斥量上锁的顺序一致就不会死锁
2)使用std::lock()函数模板,内部机制:如果互斥量中有一个没锁柱,会一直等待,等所有互斥量都锁住才会往下走,要么所有互斥量多锁住,要么都没锁,只有一个锁了会立即把已经锁的解锁。
注意:
使用模板也需要用unlock分别解锁每一个互斥量。
以下代码时产生死锁的代码:
#include <thread>
#include <iostream>
#include <vector>
#include <list>
#include <Windows.h>
#include <mutex>
using namespace std;
class RecvQueue {
public:
void inMsgRecvQueue() {
for (int i = 0; i < 100000; ++i) {
cout << "inMsgRecvQueue() start, push back one element: " << i << endl;
my_mutex1.lock();//读和写锁的顺序不一致产生死锁
my_mutex2.lock();//读和写锁的顺序不一致产生死锁
msgRecvQueue.push_back(i);
my_mutex1.unlock();
my_mutex2.unlock();
}
}
bool outMsgLULProc(int &command) {
my_mutex2.lock();//读和写锁的顺序不一致产生死锁
my_mutex1.lock();//读和写锁的顺序不一致产生死锁
if (!msgRecvQueue.empty()) {
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
my_mutex1.unlock();
my_mutex2.unlock();
return true;
}
my_mutex1.unlock();
my_mutex2.unlock();
return false;
}
void outMsgRecvQueue() {
for (int i = 0; i < 100000; ++i) {
int command = 0;
bool result = outMsgLULProc(command);
if (result){
cout << "outMsgRecvQueue is start, pop one element:" << command << endl;
}
else {
cout << "outMsgRecvQueue is empty!" << endl;
}
}
}
private:
std::list<int> msgRecvQueue;
mutex my_mutex1;
mutex my_mutex2;
};
void main() {
RecvQueue myobj;
thread myoutqueue(&RecvQueue::outMsgRecvQueue, &myobj);
thread myinqueue(&RecvQueue::inMsgRecvQueue, &myobj);
myoutqueue.join();
myinqueue.join();
}