保护共享数据,操作时,某个线程 用代码把共享数据锁住、操作数据、解锁;其他想操作共享数据的线程必须等待解锁,锁定住,操作,解锁
一、互斥量(mutex)的基本概念
互斥量就是个类对象,可以理解为一把锁,多个线程尝试用lock()成员函数来加锁,只有一个线程能锁定成功(成功的标志是lock()函数返回),如果没有锁成功,那么流程将卡在lock()这里不断尝试去锁定。
互斥量使用要小心,保护数据不多也不少,少了达不到效果,多了影响效率。
二、互斥量的用法
包含mutex 头文件(好像也可以不加)
2.1 lock(),unlock()
步骤:1.lock(),2.操作共享数据,3.unlock()。
lock()和unlock()要成对使用,有lock()必然要有unlock,每调用一次lock(),必然应该调用一次unlock();
不应该也不允许调用1次lock()却调用了2次unlock(),也不允许调用2次lock()却调用1次unlock(),这些非对称数量的调用都会导致代码的不稳定甚至崩溃
#include <map>
#include <string>
#include <thread>
#include <list>
#include <mutex>
#include <iostream>
#include <vector>
using namespace std;
class A
{
public:
//把收到的消息(玩家命令)入到一个队列的线程
void inMsgRecvQueue()
{
for (int i = 0; i < 100000; ++i)
{
cout << "inMsgReceiveQueue 执行,插入一个元素" << i << endl;
//数字i即为服务器收到的命令,插入到list中,即收到十万个玩家不断向消息队列中发玩家命令
my_mutex.lock();
msgReceiveQueue.push_back(i);
my_mutex.unlock();
}
return;
}
bool outMsgLULProc(int &command) {
my_mutex.lock();
if (!msgReceiveQueue.empty())
{
//消息不为空,则取出数据
command = msgReceiveQueue.front();//返回第一个元素,但不检查元素是否存在
msgReceiveQueue.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()执行,取出一个元素" << endl;
}
else {
//消息队列为空
cout << "目前消息队列为空" << i << endl;
}
}
cout << "end" << endl;
}
private:
list<int> msgReceiveQueue; //list容器,用于代表玩家发送给服务器的命令
mutex my_mutex;//创建了一个互斥量
};
int main()
{
//用成员函数作为线程的方法来写线程
A myobja;
thread myOutMsgObj(&A::outMsgRecvQueue, &myobja); //取对象的地址传参(可以理解为引用)
thread myInMsgObj(&A::inMsgRecvQueue, &myobja);
myInMsgObj.join();
myOutMsgObj.join();
//程序运行会引发异常,因为没有锁住共享数据,解决这个问题,需要引入互斥量
cout << "I Love China" << endl;//最后执行这句,整个进程退出
return 0;
}
2.2 lock_guard类模板
lock_guard guard(myMutex);直接取代lock()和unlock(),也就是说用了lock_guard之后,再不能使用lock()和unlock()了
lock_guard构造函数执行了mutex::lock();在作用域结束时,调用析构函数,执行mutex::unlock()
#include <map>
#include <string>
#include <thread>
#include <list>
#include <mutex>
#include <iostream>
#include <vector>
using namespace std;
class A
{
public:
//把收到的消息(玩家命令)入到一个队列的线程
void inMsgRecvQueue()
{
for (int i = 0