目录
案例:
共享数据:
1、互斥量引入
方法一:lock()、unlock()
方法二:std::lock_guard()
2、死锁
解决方案:
案例:游戏服务器,收到玩家的指令,然后处理指令,使用一个list容器来收集指令,用两个线程来维护接收、处理指令的操作。
共享数据: 如果对于共享数据是只读操作的话,不需要考虑互斥量问题 如果对共享数据需要进行读写操作的话,需要引入互斥量,不然当一个线程正在修改共享变量的时候,另一个线程需要访问,但是此时共享数据已经被改了(火车站售票,同时买票)code1:对共享数据进行操作,没有引入互斥量,程序崩溃
#include
#include
#include
#include
#include
using namespace std;
class A
{
public:
//把玩家收到的消息放到一个队列的线程中
void inMsgRecvQueue()
{
for (int i = 0; i < 100000; i++)
{
cout << "inMsgRecvQueue()执行,插入数据" << i << endl;
msgRecvQueue.push_back(i);
}
}
bool outMsgLULProc(int &command)
{
if (!msgRecvQueue.empty())
{
command = msgRecvQueue.front();
msgRecvQueue.pop_front();;
return true;
}
return false;
}
//把容器里面的消息取出来处理
void outMsgRecvQueue()
{
for (int i = 0; i < 100000; i++)
{
int command = 0;
bool result = outMsgLULProc(command);
if (result == true)
{
cout << "outMsgRecvQueue()执行,取出后一个元素" << command << endl;
//.....其他处理command的代码
}
else
{
cout << "outMsgRecvQueue为空" << endl;
}
}
cout << "ending" << endl;
}
private:
std::list msgRecvQueue;// 玩家发过来的命令
};
int main()
{
A myobj;
std::thread myinthread(&A::inMsgRecvQueue, &myobj);
std::thread myoutthread(&A::outMsgRecvQueue, &myobj);
myinthread.join();
myoutthread.join();
cout << "i love china" << endl;
return 0;
}
1、互斥量引入
方法一:lock()、unlock()
#include
std::mutex mymutex;// 一般情况下一个互斥量保护一个共享数据块。通过这个来锁住一段代码
mymutex.lock() 对应一个 mymutex.unlock()
每一个可能的出口都要有一个mymutex.unlock()
#include
#include
#include
#include
#include
using namespace std;
class A
{
public:
//把玩家收到的消息放到一个队列的线程中
void inMsgRecvQueue()
{
for (int i = 0; i < 100000; i++)
{
cout << "inMsgRecvQueue()执行,插入数据" << i << endl;
mymutex1.lock();
msgRecvQueue.push_back(i);
mymutex1.unlock();
}
}
bool outMsgLULProc(int &command)
{
mymutex.lock();
if (!msgRecvQueue.empty())
{
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
mymutex.unlock();
return true;
}
mymutex.unlock();
return false;
}
//把容器里面的消息取出来处理
void outMsgRecvQueue()
{
for (int i = 0; i < 100000; i++)
{
int command = 0;
bool result = outMsgLULProc(command);
if (result == true)
{
cout << "outMsgRecvQueue()执行,取出后一个元素" << command << endl;
//.....其他处理command的代码
}
else
{
cout << "outMsgRecvQueue为空" << endl;
}
}
cout << "ending" << endl;
}
private:
std::list msgRecvQueue;// 玩家发过来的命令
std::mutex mymutex;
};
int main()
{
A myobj;
std::thread myinthread(&A::inMsgRecvQueue, &myobj);
std::thread myoutthread(&A::outMsgRecvQueue, &myobj);
myinthread.join();
myoutthread.join();
cout << "i love china" << endl;
return 0;
}
方法二:std::lock_guard()
类模板std::lock_guard sbguard(mymutex);
其构造函数里面有一个lock(),析构函数里面有一个unlock(),可以通过{ }的手法来控制析构函数的执行时间。
#include
#include
#include
#include
#include
using namespace std;
class A
{
public:
//把玩家收到的消息放到一个队列的线程中
void inMsgRecvQueue()
{
for (int i = 0; i < 100000; i++)
{
cout << "inMsgRecvQueue()执行,插入数据" << i << endl;
std::lock_guard sb_guard(mymutex);
msgRecvQueue.push_back(i);
}
}
bool outMsgLULProc(int &command)
{
std::lock_guard sbguard(mymutex);
if (!msgRecvQueue.empty())
{
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
return true;
}
return false;
}
//把容器里面的消息取出来处理
void outMsgRecvQueue()
{
for (int i = 0; i < 100000; i++)
{
int command = 0;
bool result = outMsgLULProc(command);
if (result == true)
{
cout << "outMsgRecvQueue()执行,取出后一个元素" << command << endl;
//.....其他处理command的代码
}
else
{
cout << "outMsgRecvQueue为空" << endl;
}
}
cout << "ending" << endl;
}
private:
std::list msgRecvQueue;// 玩家发过来的命令
std::mutex mymutex;
};
int main()
{
A myobj;
std::thread myinthread(&A::inMsgRecvQueue, &myobj);
std::thread myoutthread(&A::outMsgRecvQueue, &myobj);
myinthread.join();
myoutthread.join();
cout << "i love china" << endl;
return 0;
}
2、死锁
定义:A、B两个线程和两个锁,JIN 和 YIN,当A线程在已经锁了JIN的时候,想要去锁YIN,但是此时B把YIN给锁住了,想去锁JIN,所以A、B两个线程都在等待,这样就形成了死锁。
张三:在北京等李四,一直等。
李四:在杭州等张三,一直等。
两人等到死都没等到。
#include
#include
#include
#include
#include
using namespace std;
class A
{
public:
//把玩家收到的消息放到一个队列的线程中
void inMsgRecvQueue()
{
for (int i = 0; i < 100000; i++)
{
cout << "inMsgRecvQueue()执行,插入数据" << i << endl;
mymutex1.lock();
mymutex2.lock();
msgRecvQueue.push_back(i);
mymutex1.unlock();
mymutex2.unlock();
}
}
bool outMsgLULProc(int &command)
{
mymutex2.lock();
// ..... 在这两个锁之间还有很多处理的代码。可以保护不同的数据共享块。
mymutex1.lock();
if (!msgRecvQueue.empty())
{
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
mymutex1.unlock();
mymutex2.unlock();
return true;
}
mymutex1.unlock();
mymutex2.unlock();
return false;
}
//把容器里面的消息取出来处理
void outMsgRecvQueue()
{
for (int i = 0; i < 100000; i++)
{
int command = 0;
bool result = outMsgLULProc(command);
if (result == true)
{
cout << "outMsgRecvQueue()执行,取出后一个元素" << command << endl;
//.....其他处理command的代码
}
else
{
cout << "outMsgRecvQueue为空" << endl;
}
}
cout << "ending" << endl;
}
private:
std::list msgRecvQueue;// 玩家发过来的命令
std::mutex mymutex1;
std::mutex mymutex2;
};
int main()
{
A myobj;
std::thread myinthread(&A::inMsgRecvQueue, &myobj);
std::thread myoutthread(&A::outMsgRecvQueue, &myobj);
myinthread.join();
myoutthread.join();
cout << "i love china" << endl;
return 0;
}
解决方案:
顺序lock的顺序一致即可,std::lock_guard同理
#include
#include
#include
#include
#include
using namespace std;
class A
{
public:
//把玩家收到的消息放到一个队列的线程中
void inMsgRecvQueue()
{
for (int i = 0; i < 100000; i++)
{
cout << "inMsgRecvQueue()执行,插入数据" << i << endl;
mymutex1.lock();
mymutex2.lock();
msgRecvQueue.push_back(i);
mymutex1.unlock();
mymutex2.unlock();
}
}
bool outMsgLULProc(int &command)
{
mymutex1.lock();
// ..... 在这两个锁之间还有很多处理的代码。可以保护不同的数据共享块。
mymutex2.lock();
if (!msgRecvQueue.empty())
{
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
//mymutex1.unlock();
//mymutex2.unlock();
return true;
}
mymutex1.unlock();
mymutex2.unlock();
return false;
}
//把容器里面的消息取出来处理
void outMsgRecvQueue()
{
for (int i = 0; i < 100000; i++)
{
int command = 0;
bool result = outMsgLULProc(command);
if (result == true)
{
cout << "outMsgRecvQueue()执行,取出后一个元素" << command << endl;
//.....其他处理command的代码
}
else
{
cout << "outMsgRecvQueue为空" << endl;
}
}
cout << "ending" << endl;
}
private:
std::list msgRecvQueue;// 玩家发过来的命令
std::mutex mymutex1;
std::mutex mymutex2;
};
int main()
{
A myobj;
std::thread myinthread(&A::inMsgRecvQueue, &myobj);
std::thread myoutthread(&A::outMsgRecvQueue, &myobj);
myinthread.join();
myoutthread.join();
cout << "i love china" << endl;
return 0;
}
使用std::lock():以此可以锁住两个或者两个以上的锁(一个不可以),原理是,只有当lock的所有锁都锁住了之后,才会继续执行下面的代码,如果有一部分锁没有锁上,那么其将会释放已经上过的锁,然后过一段时间在来判断是否所有的锁都已经锁上。故而:搭配unlock使用;搭配std::lock_guard,但是要引入结构对象std::adopt_lock,来告诉lock_gurad的构造函数不要再进行lock操作了。
#include
#include
#include
#include
#include
using namespace std;
class A
{
public:
//把玩家收到的消息放到一个队列的线程中
void inMsgRecvQueue()
{
for (int i = 0; i < 100000; i++)
{
cout << "inMsgRecvQueue()执行,插入数据" << i << endl;
std::lock(mymutex1, mymutex2);
msgRecvQueue.push_back(i);
mymutex1.unlock();
mymutex2.unlock();
}
}
bool outMsgLULProc(int &command)
{
std::lock(mymutex1, mymutex2);
std::lock_guard sbguard1(mymutex1, std::adopt_lock);
std::lock_guard sbguard2(mymutex2, std::adopt_lock);
if (!msgRecvQueue.empty())
{
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
return true;
}
return false;
}
//把容器里面的消息取出来处理
void outMsgRecvQueue()
{
for (int i = 0; i < 100000; i++)
{
int command = 0;
bool result = outMsgLULProc(command);
if (result == true)
{
cout << "outMsgRecvQueue()执行,取出后一个元素" << command << endl;
//.....其他处理command的代码
}
else
{
cout << "outMsgRecvQueue为空" << endl;
}
}
cout << "ending" << endl;
}
private:
std::list msgRecvQueue;// 玩家发过来的命令
std::mutex mymutex1;
std::mutex mymutex2;
};
int main()
{
A myobj;
std::thread myinthread(&A::inMsgRecvQueue, &myobj);
std::thread myoutthread(&A::outMsgRecvQueue, &myobj);
myinthread.join();
myoutthread.join();
cout << "i love china" << endl;
return 0;
}
作者:1 每逢大事有静气