熱線電話(hua):0755-23712116
郵箱:contact@legoupos.cn
地址:深圳市寶安區沙井街道后(hou)亭茅洲山工(gong)業園工(gong)業大廈全至科技(ji)創新園科創大廈2層2A
看到“死鎖(suo)”二(er)字,你是不是慌得不知所措。死鎖(suo),顧(gu)名(ming)思(si)義就(jiu)是這個(ge)鎖(suo)死掉了,再也動不了了。那死鎖(suo)是怎么(me)產(chan)生的(de)呢?當你對某(mou)個(ge)資源(yuan)上鎖(suo)后,卻遲遲沒有釋放或(huo)者根(gen)本就(jiu)無(wu)法釋放,導致別的(de)線程(cheng)無(wu)法獲得該資源(yuan)的(de)訪問權限,進(jin)而(er)(er)程(cheng)序無(wu)法運行(xing)下去(qu),有點像是阻(zu)塞(sai)的(de)現象。但(dan)是阻(zu)塞(sai)是一(yi)種(zhong)正(zheng)常現象,而(er)(er)死鎖(suo)可以(yi)說是一(yi)種(zhong)bug,必須要處理。
那么(me)我現(xian)在就(jiu)舉(ju)個死鎖(suo)的例子(zi),來分析分析。
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
mutex mt1;
mutex mt2;
void thread1()
{
cout << "thread1 begin" << endl;
lock_guard<mutex> guard1(mt1);
this_thread::sleep_for(chrono::seconds(1));
lock_guard<mutex> guard2(mt2);
cout << "hello thread1" << endl;
}
void thread2()
{
cout << "thread2 begin" << endl;
lock_guard<mutex> guard1(mt2);
this_thread::sleep_for(chrono::seconds(1));
lock_guard<mutex> guard2(mt1);
cout << "hello thread2" << endl;
}
int main()
{
thread t1(thread1);
thread t2(thread2);
t1.join();
t2.join();
cout << "thread end" << endl;
return 0;
}
因為(wei)程序(xu)運(yun)行的是非(fei)常快的,所以為(wei)了產(chan)生死(si)鎖現(xian)象,我們各自休眠了1秒。
運行以(yi)上程序(xu)可以(yi)發現,程序(xu)在輸出(chu)完“thread1 beginthread2 begin”后,就卡在那里(li),程序(xu)運行可能發生(sheng)了以(yi)下這種(zhong)情況(kuang):
thread1 thread2
mt1.lock() mt2.lock()
//死鎖 //死鎖
mt2.lock() mt1.lock()
thread1中的mt2在(zai)等(deng)待(dai)著thread2的mt2釋放(fang)鎖,而(er)thead2中mt1卻也在(zai)等(deng)待(dai)著thread1的mt1釋放(fang)鎖,互相(xiang)都在(zai)等(deng)待(dai)著對方(fang)釋放(fang)鎖,進而(er)產(chan)生了死鎖。必須強調(diao)的是,這是一種bug,必須避免。那(nei)么如何避免這種情況(kuang)呢?
1、每次都先(xian)鎖同(tong)一(yi)個(ge)鎖
比如像上面thread1和(he)thread2線程,我(wo)們每次都先(xian)鎖mt1,再鎖mt2,就不會發生死鎖現(xian)象(xiang)。
2、給鎖(suo)定義一個層(ceng)次(ci)的屬(shu)性,每(mei)次(ci)按(an)層(ceng)次(ci)由(you)高到低的順序上鎖(suo),這個原(yuan)理也是每(mei)次(ci)都(dou)先鎖(suo)同一個鎖(suo)。
C++標準庫中提供了std::lock()函(han)數,能夠保(bao)證將多個互斥鎖同時(shi)上鎖。
std::lock(mt1, mt2);
那(nei)么既(ji)然在最前面就(jiu)已經上(shang)鎖了,后面就(jiu)不需要(yao)上(shang)鎖了,而(er)C++標準庫并(bing)沒(mei)有提供std::unlock()的用法,所以還是(shi)需要(yao)用到lock_guard,但是(shi)需要(yao)修改一點。加個std::adopt_lock就(jiu)可以了。
lock_guard<mutex> guard1(mt1, adopt_lock);
lock_guard<mutex> guard2(mt2, adopt_lock);
這個表示(shi)構(gou)造函(han)數的時(shi)候(hou)不要(yao)給(gei)我上鎖,到析構(gou)的時(shi)候(hou)你要(yao)記得給(gei)我解鎖。
這個就(jiu)是死(si)鎖(suo)的一(yi)些解決方(fang)法,同時大家一(yi)定(ding)要記得(de)盡(jin)量不要一(yi)段(duan)定(ding)義(yi)域(yu)內多次使(shi)用互(hu)斥鎖(suo),如果(guo)不可避免的要使(shi)用,一(yi)定(ding)要記得(de)給鎖(suo)定(ding)義(yi)順序,或者使(shi)用要使(shi)用std::lock()上鎖(suo)。
相(xiang)關閱讀: