C++

Parallel Tutorial 3: Deadlock (Implement with C++)

我們假設一個開銀行保險箱的例子,假如今天Tim跟Ryan兩個人各有一把鑰匙,兩個人都必須要拿到兩支鑰匙才能夠開保險箱,而Tim總是先拿自己的鑰匙去開之後,才去找Ryan借鑰匙;相反的,Ryan則是先拿自己的鑰匙開之後,才去找Tim拿第二支鑰匙,如此一來,兩個人各自把自己的鑰匙用上後,就會發現對方的鑰匙也再使用,因此必須要等待,這樣兩個人永遠都在互相等待,所以這個保險箱就永遠打不開。

Deadlock 版本

#include <thread>
#include <mutex>
#include <chrono>

int money = 10000;

void bankStaff(std::mutex &first_key, std::mutex &second_key)
{
    while(money > 0)
    {
        first_key.lock();
        second_key.lock();
        if(money)
            money--;
        second_key.unlock();;
        first_key.unlock();
    }
}

int main()
{
    std::mutex ryanKey, timKey;
    std::thread ryan(bankStaff, std::ref(ryanKey), std::ref(timKey));
    std::thread tim(bankStaff, std::ref(timKey), std::ref(ryanKey));
    ryan.join();
    tim.join();
    printf("Completed!");
}

避免Deadlock的版本 1 : 使用一致的順序

兩者使用mutex順序應該要一致,以這個case來說,兩個人都優先使用Ryan的鑰匙,之後才去拿Tim的鑰匙,這樣不會有兩邊互卡的問題

// DeadLock
#include <thread>
#include <mutex>
#include <chrono>

int money = 10000;

void bankStaff(std::mutex &first_key, std::mutex &second_key)
{
    while(money > 0)
    {
        first_key.lock();
        second_key.lock();
        if(money)
            money--;
        second_key.unlock();;
        first_key.unlock();
    }
}

int main()
{
    std::mutex ryanKey, timKey;
    std::thread ryan(bankStaff, std::ref(ryanKey), std::ref(timKey));
    std::thread tim(bankStaff, std::ref(ryanKey), std::ref(timKey));
    ryan.join();
    tim.join();
    printf("Completed!");
}

避免Deadlock的版本 2 : 使用scoped_block

C++ 17 以後才有的新特性,進入scoped的時候會將兩的mutex上鎖,退出{ }的時候,將兩個mutex同時釋放掉。



void bankStaff(std::mutex &first_key, std::mutex &second_key)
{
    while(money > 0)
    {
        std::scoped_lock lock(first_key, second_key);
        if(money)
            money--;
    }
}

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *