編程代碼
新聞詳情

C++11多線程編程(八)——死鎖問題

發布時(shí)間:2021-01-07 14:00:41 浏覽次數:2611

一(yī / yì /yí)、死鎖現象

看到(dào)“死鎖”二字,你是(shì)不(bù)是(shì)慌得不(bù)知所措。死鎖,顧名思義就(jiù)是(shì)這(zhè)個(gè)鎖死掉了(le/liǎo),再也(yě)動不(bù)了(le/liǎo)了(le/liǎo)。那死鎖是(shì)怎麽産生的(de)呢?當你對某個(gè)資源上(shàng)鎖後,卻遲遲沒有釋放或者根本就(jiù)無法釋放,導緻别的(de)線程無法獲得該資源的(de)訪問權限,進而(ér)程序無法運行下去,有點像是(shì)阻塞的(de)現象。但是(shì)阻塞是(shì)一(yī / yì /yí)種正常現象,而(ér)死鎖可以(yǐ)說(shuō)是(shì)一(yī / yì /yí)種bug,必須要(yào / yāo)處理。

C++11多線程編程(八)——死鎖問題

那麽我現在(zài)就(jiù)舉個(gè)死鎖的(de)例子(zǐ),來(lái)分析分析。

#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;
}

二、死鎖分析

因爲(wéi / wèi)程序運行的(de)是(shì)非常快的(de),所以(yǐ)爲(wéi / wèi)了(le/liǎo)産生死鎖現象,我們各自休眠了(le/liǎo)1秒。

運行以(yǐ)上(shàng)程序可以(yǐ)發現,程序在(zài)輸出(chū)完“thread1 beginthread2 begin”後,就(jiù)卡在(zài)那裏,程序運行可能發生了(le/liǎo)以(yǐ)下這(zhè)種情況:

thread1              thread2
mt1.lock()           mt2.lock()
//死鎖               //死鎖
mt2.lock()           mt1.lock()

thread1中的(de)mt2在(zài)等待着thread2的(de)mt2釋放鎖,而(ér)thead2中mt1卻也(yě)在(zài)等待着thread1的(de)mt1釋放鎖,互相都在(zài)等待着對方釋放鎖,進而(ér)産生了(le/liǎo)死鎖。必須強調的(de)是(shì),這(zhè)是(shì)一(yī / yì /yí)種bug,必須避免。那麽如何避免這(zhè)種情況呢?

三、死鎖解決

1、每次都先鎖同一(yī / yì /yí)個(gè)鎖

比如像上(shàng)面thread1和(hé / huò)thread2線程,我們每次都先鎖mt1,再鎖mt2,就(jiù)不(bù)會發生死鎖現象。

2、給鎖定義一(yī / yì /yí)個(gè)層次的(de)屬性,每次按層次由高到(dào)低的(de)順序上(shàng)鎖,這(zhè)個(gè)原理也(yě)是(shì)每次都先鎖同一(yī / yì /yí)個(gè)鎖。

C++标準庫中提供了(le/liǎo)std::lock()函數,能夠保證将多個(gè)互斥鎖同時(shí)上(shàng)鎖。

std::lock(mt1, mt2);

那麽既然在(zài)最前面就(jiù)已經上(shàng)鎖了(le/liǎo),後面就(jiù)不(bù)需要(yào / yāo)上(shàng)鎖了(le/liǎo),而(ér)C++标準庫并沒有提供std::unlock()的(de)用法,所以(yǐ)還是(shì)需要(yào / yāo)用到(dào)lock_guard,但是(shì)需要(yào / yāo)修改一(yī / yì /yí)點。加個(gè)std::adopt_lock就(jiù)可以(yǐ)了(le/liǎo)。

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

這(zhè)個(gè)表示構造函數的(de)時(shí)候不(bù)要(yào / yāo)給我上(shàng)鎖,到(dào)析構的(de)時(shí)候你要(yào / yāo)記得給我解鎖。

這(zhè)個(gè)就(jiù)是(shì)死鎖的(de)一(yī / yì /yí)些解決方法,同時(shí)大(dà)家一(yī / yì /yí)定要(yào / yāo)記得盡量不(bù)要(yào / yāo)一(yī / yì /yí)段定義域内多次使用互斥鎖,如果不(bù)可避免的(de)要(yào / yāo)使用,一(yī / yì /yí)定要(yào / yāo)記得給鎖定義順序,或者使用要(yào / yāo)使用std::lock()上(shàng)鎖。

相關閱讀:

在(zài)線客服 雙翌客服
客服電話
  • 0755-23712116
  • 13310869691