1. 程式人生 > 實用技巧 >C++11多執行緒程式設計(八)——死鎖問題

C++11多執行緒程式設計(八)——死鎖問題

一、死鎖現象

看到“死鎖”二字,你是不是慌得不知所措。死鎖,顧名思義就是這個鎖死掉了,再也動不了了。那死鎖是怎麼產生的呢?當你對某個資源上鎖後,卻遲遲沒有釋放或者根本就無法釋放,導致別的執行緒無法獲得該資源的訪問許可權,進而程式無法執行下去,有點像是阻塞的現象。但是阻塞是一種正常現象,而死鎖可以說是一種bug,必須要處理。

那麼我現在就舉個死鎖的例子,來分析分析。

 1 #include <iostream>
 2 #include <thread>
 3 #include <mutex>
 4 using namespace std;
 5  
 6
mutex mt1; 7 mutex mt2; 8 void thread1() 9 { 10 cout << "thread1 begin" << endl; 11 lock_guard<mutex> guard1(mt1); 12 this_thread::sleep_for(chrono::seconds(1)); 13 lock_guard<mutex> guard2(mt2); 14 cout << "hello thread1" << endl; 15 } 16 void thread2()
17 { 18 cout << "thread2 begin" << endl; 19 lock_guard<mutex> guard1(mt2); 20 this_thread::sleep_for(chrono::seconds(1)); 21 lock_guard<mutex> guard2(mt1); 22 cout << "hello thread2" << endl; 23 } 24 25 int main() 26 { 27 thread t1(thread1); 28 thread t2(thread2);
29 t1.join(); 30 t2.join(); 31 cout << "thread end" << endl; 32 return 0; 33 }

二、死鎖分析

因為程式執行的是非常快的,所以為了產生死鎖現象,我們各自休眠了1秒。

執行以上程式可以發現,程式在輸出完“thread1 beginthread2 begin”後,就卡在那裡,程式執行可能發生了以下這種情況:

1 thread1 thread2
2 mt1.lock() mt2.lock()
3 //死鎖 //死鎖
4 mt2.lock() mt1.lock()

thread1中的mt2在等待著thread2的mt2釋放鎖,而thead2中mt1卻也在等待著thread1的mt1釋放鎖,互相都在等待著對方釋放鎖,進而產生了死鎖。必須強調的是,這是一種bug,必須避免。那麼如何避免這種情況呢?

三、死鎖解決

1、每次都先鎖同一個鎖

比如像上面thread1和thread2執行緒,我們每次都先鎖mt1,在鎖mt2,就不會發生死鎖現象。

2、給鎖定義一個層次的屬性,每次按層次由高到低的順序上鎖,這個原理也是每次都先鎖同一個鎖。

C++標準庫中提供了std::lock()函式,能夠保證將多個互斥鎖同時上鎖。

std::lock(mt1, mt2);

那麼既然在最前面就已經上鎖了,後面就不需要上鎖了,而C++標準庫並沒有提供std::unlock()的用法,所以還是需要用到lock_guard,但是需要修改一點。加個std::adopt_lock就可以了。

1 lock_guard<mutex> guard1(mt1, adopt_lock);
2 lock_guard<mutex> guard2(mt2, adopt_lock);

這個表示建構函式的時候不要給我上鎖,到析構的時候你要記得給我解鎖。

這個就是死鎖的一些解決方法,同時大家一定要記得儘量不要一段定義域內多次使用互斥鎖,如果不可避免的要使用,一定要記得給鎖定義順序,或者使用要使用std::lock()上鎖。

更多精彩內容,請關注同名公眾:一點筆記alittle