簡體   English   中英

具有互斥鎖的多個鎖和可能發生死鎖

[英]Multiple locks with mutex and the possibility of a deadlock

我是線程新手並試圖理解互斥鎖。
我理解互斥鎖是一個只被一個線程挑選的對象(密鑰)(如果它被挑選然后其他線程無法選擇它並且必須等待)來訪問我們想要鎖定的代碼的某些部分。
因此,當時只有一個線程可以訪問該鎖定的代碼部分(例如共享計數器)。 其他線程必須等到互斥鎖解鎖等等。

Mutex1.Lock();
 {
     Mutex2.Lock();
     {
          // Code locked by mutex 1 and 2.
     }
     Mutex2.Unlock();

     // Code locked by mutex 1.
 }
 Mutex1.Unlock();

如果我寫多個互斥鎖會發生什么?
這兩個互斥鎖是否會被同一個線程選中? 我還讀到多個互斥鎖可能導致死鎖。
誰能解釋並提供一個例子,說明如何通過用2個互斥鎖鎖定部分代碼來導致死鎖?

以下是對您描述的內容進行編碼的安全方法:

std::mutex Mutex1;
std::mutex Mutex2;

void
test()
{
    using namespace std;
    lock(Mutex1, Mutex2);  // no deadlock!
    lock_guard<mutex> lk1{Mutex1, adopt_lock};
    {
        lock_guard<mutex> lk2{Mutex2, adopt_lock};
        // Code locked by mutex 1 and 2.
    }   // lk2.unlock()
    // Code locked by mutex 1.
}   // lk1.unlock()

此代碼無法死鎖,因為std::lock(Mutex1, Mutex2)鎖定兩個互斥鎖,同時避免死鎖(通過某些內部算法)。 使用std::lock一個優點是您不必記住鎖定互斥鎖所需的順序(這使得在大型代碼庫中維護更容易)。 但缺點是您需要在代碼中的單個點鎖定兩個鎖。 如果您無法同時鎖定它們,那么您必須按照其他答案描述的那樣回退到訂購。

此代碼也是異常安全的,因為如果在任何地方拋出任何異常,則在異常傳播時解鎖任何被鎖定的內容。

一個線程可以容納多個鎖,是的。 即使它只獲得了一個互斥鎖,也可能發生死鎖。查看工作流程:

線程A.

. 
.
.
lock mutex1
.
<---- Context switch! ----->

線程B.

.
.
.
.
lock mutex2
.
.
.
try lock mutex1 ----> BLOCKED UNTIL THREAD A RELEASES LOCK!

線程A.

.
.
.
try lock mutex2 ---> BLOCKED UNTIL THREAD B RELEASES LOCK!

僵局!

讀取這個 ,一些互斥體類型,如PTHREAD_MUTEX_NORMAL可能會導致線程自身死鎖。

.
.
.
lock mutex
.
.
.
try lock

如果我寫多個互斥鎖會發生什么? 這兩個互斥鎖是否會被同一個線程選中?

線程可以同時保存任意數量的互斥鎖。 在您的示例代碼中,進入受Mutex1保護的區域的線程將嘗試獲取Mutex2 ,等待另一個線程在必要時首先釋放它。 您提交的代碼中沒有特別的理由認為它不會成功。

我還讀到多個互斥鎖可能導致死鎖。 任何人都可以解釋我如何通過鎖定部分代碼與2個互斥鎖導致死鎖?

假設有兩個線程,一個持有mutex1而另一個持有mutex2(在這種情況下,至少后者必須運行與你的偽代碼不同的東西)。 現在假設每個線程都試圖獲取另一個互斥鎖而不釋放它已經擁有的互斥鎖。 第一個線程必須獲取mutex2才能繼續,並且在另一個線程釋放之前不能這樣做。 第二個線程必須獲取mutex1才能繼續,並且在另一個線程釋放之前不能這樣做。 人機工程學, 兩個線程不能繼續-這是一個僵局。

一般規則是這樣的:如果有一組互斥體,所有兩個或多個線程可能都想要同時保持,那么每個線程在獲取它們的任何子集時都必須遵循這些互斥體的固定相對排序。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM