多線程 mutex的理解
mutex,我的理解是每個mutex對象都是一個帶鎖頭的門,這個門有兩個狀態,門開着和門關着,感覺像是廢話。。。
當想查看門的里東西,或者把東西放進門里,或者從門里拿出東西前,都需要看看,門是否是打開的。
- 如果門是打開的,就要進去后趕緊把門關上。關上后,就可以查看屋子里的東西,放東西到屋子里,從屋子里拿東西。
- 如果門是關着的,就要在外面等着,直到有人出來時,把門打開了,你才能進去。
每個mutex都是不同的門,當你用mutex a鎖上了一個門,就只能用mutex a去打開,用mutex b是打不開,切記。
例子:用mutex a鎖門,用metex b去開門,結果沒打開,就導致了程序的死鎖。
注意:這個程序專門為了測試,mutex的問題。
#include <list>
#include <iostream>
#include <mutex>
#include <algorithm>
#include <thread>
#include <unistd.h>
using namespace std;
class data_protect{
public:
list<int> alist{1,2};
mutex m;
mutex m1;
public:
void add_list(int val){
m.lock(); //----------------①
alist.push_back(val);
}
bool contains(int val){
m1.unlock();//----------------------②
return find(alist.begin(), alist.end(), val) != alist.end();
}
};
void func(data_protect& dp){
dp.add_list(12);
}
int main(){
data_protect dp;
thread t(func, ref(dp));
//t.join();
t.detach();//---------------③
//sleep(1);
dp.add_list(12);//----------------④
if(dp.contains(12)){//------------------⑤
cout << "contains 12" << endl;
}
for(auto& s : dp.alist){
cout << s << endl;
}
pthread_exit(NULL);
}
執行結果:死鎖,程序永遠在等待鎖的打開。
執行結果分析:
從③處開始就開了一個新的線程a,線程a調用了add_list()方法,add_list方法里,在①處是用m去上的鎖。main函數線程在④處也調用了,add_list()方法,進去后,發現是上鎖的狀態,所以就阻塞在哪里,等着鎖打開后,main函數線程好進去,然后在⑤處調用了contains方法,contains方法試圖在②處用m1去解m的鎖,所以就解不開①處的鎖,所以就導致了一個線程一直等在①處的鎖的地方,就導致了死鎖。
如果把②處的m1.unlock();換成m.unlock();就能解開鎖了,就不會導致死鎖。
想說明的東西,用哪個mutex上的鎖,就得用哪個mutex去解鎖。
mutex的正確使用方法:不是直接用調用mutex的lock,unlock方法。理由是在lock和unlock中間的某段代碼如果崩潰掉,就會導致unlock方法沒有被執行,也就導致了,鎖沒有解開,別線程再來訪問時,就變成了死鎖。
所以使用:std::lock_guard<std::mutex>,它的好處是,即使發生了異常也能自動解鎖。
例子:
#include <list>
#include <iostream>
#include <mutex>
#include <algorithm>
#include <thread>
#include <unistd.h>
using namespace std;
class data_protect{
public:
list<int> alist{1,2};
mutex m;
public:
void add_list(int val){
lock_guard<mutex> g(m);
alist.push_back(val);
}
bool contains(int val){
lock_guard<mutex> g(m);
return find(alist.begin(), alist.end(), val) != alist.end();
}
};
void func(data_protect& dp){
dp.add_list(12);
}
int main(){
data_protect dp;
thread t(func, ref(dp));
//t.join();
t.detach();
//sleep(1);
dp.add_list(12);
if(dp.contains(12)){
cout << "contains 12" << endl;
}
for(auto& s : dp.alist){
cout << s << endl;
}
pthread_exit(NULL);
}