C++ 互斥量、死锁

Viola ·
更新时间:2024-11-15
· 513 次阅读

目录

案例:

共享数据:

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 每逢大事有静气



死锁 互斥 C++ c+

需要 登录 后方可回复, 如果你还没有账号请 注册新账号