<二>執行緒間互斥-mutex互斥鎖和lock_guard
阿新 • • 發佈:2022-12-12
多執行緒程式
競態條件:多執行緒程式執行的結果是一致的,不會隨著CPU對執行緒不同的呼叫順序而產生不同的執行結果.
解決?:互斥鎖 mutex
經典的賣票問題,三個執行緒賣100張票
程式碼1
#include <iostream> #include <thread> #include <list> #include <mutex> int ticketCount = 100; std::mutex mtx;//互斥鎖 void sellTicket(int window) { while (ticketCount > 0) { mtx.lock(); std::cout << "視窗" << window << "銷售" << ticketCount << std::endl; ticketCount--; mtx.unlock(); std::this_thread::sleep_for(std::chrono::milliseconds(50)); } }//end int main() { std::list<std::thread> tlist; for (int i = 0; i < 3; i++) { tlist.push_back(std::thread(sellTicket,i)); } for (std::thread & t : tlist) { t.join(); } system("pause"); return 0; }
上面程式碼的問題...
while (ticketCount > 0) { mtx.lock(); std::cout << "視窗" << window << "銷售" << ticketCount << std::endl; ticketCount--; mtx.unlock(); std::this_thread::sleep_for(std::chrono::milliseconds(50)); } 如果ticketCount =1 ,當前有一個執行緒A while (ticketCount > 0)為true,執行緒A還沒執行ticketCount--完成時,cpu交給了執行緒B 執行緒B while (ticketCount > 0)也為true,進入 迴圈體內,造成了買0號票,改進如下
程式碼2
#include <iostream> #include <thread> #include <list> #include <mutex> int ticketCount = 100; std::mutex mtx;//互斥鎖 void sellTicket(int window) { while (ticketCount > 0) { mtx.lock(); if(ticketCount >0){ std::cout << "視窗" << window << "銷售" << ticketCount << std::endl; ticketCount--; } mtx.unlock(); std::this_thread::sleep_for(std::chrono::milliseconds(50)); } }//end int main() { std::list<std::thread> tlist; for (int i = 0; i < 3; i++) { tlist.push_back(std::thread(sellTicket,i)); } for (std::thread & t : tlist) { t.join(); } system("pause"); return 0; }
程式碼2還有些問題!! 如下
mtx.lock();
程式碼
程式碼
程式碼
程式碼
.....
mtx.unlock();
如果在程式碼lock()和unlock()之間 非常返回,導致mtx沒有正常unlock(),那麼出現死鎖問題 =》智慧指標 lock_gurad unique_lock
看lock_gurad
#include <iostream>
#include <thread>
#include <list>
#include <mutex>
int ticketCount = 100;
std::mutex mtx;//互斥鎖
void sellTicket(int window) {
while (ticketCount > 0) {
{
std::lock_guard<std::mutex> lock(mtx);
std::cout << "視窗" << window << "銷售" << ticketCount << std::endl;
ticketCount--;
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
}
}//end
int main() {
std::list<std::thread> tlist;
for (int i = 0; i < 3; i++) {
tlist.push_back(std::thread(sellTicket,i));
}
for (std::thread & t : tlist) {
t.join();
}
system("pause");
return 0;
}
上面的圖片中我們知道lock_gurad 的拷貝建構函式被關閉了,所以當我們遇到函式呼叫需要拷貝構造lock_guard的時候,就有障礙了,這個時候可以用unique_lock
unique_lock 轉移指標,支援帶右值得拷貝賦值,支援引數傳遞拷貝構造的,他的左值的拷貝構造也是被關閉了 看下圖