如何寫一段死鎖程式碼

安全劍客發表於2020-12-08
死鎖 是指兩個或兩個以上的程式(執行緒)在執行過程中,由於競爭資源或者由於彼此通訊而造成的一種阻塞的現象,若無外力作用,它們都將無法推進下去。此時稱系統處於死鎖 狀態或系統產生了死鎖,這些永遠在互相等待的程式稱為死鎖 程式(執行緒)。

如何寫一段死鎖程式碼如何寫一段死鎖程式碼

.NET 中的死鎖

通常的死鎖的示例都是兩個鎖,多個資源導致的死鎖,你有沒有想過一個資源也會導致死鎖,如何使用一個鎖造成死鎖呢?思考一下再看下面的程式碼:

private static readonly object Lock = new object();
public static void Test()
{
    lock (Lock)
    {
        Task.Run(TestMethod1).Wait();
    }
}
private static void TestMethod1()
{
    lock (Lock)
    {
        Console.WriteLine("xxx");
    }
}

在 Test 這個方法中首先獲取鎖,獲取鎖成功之後呼叫另外一個執行緒去呼叫 TestMethod1 方法,而 TestMethod1 方法中會再次嘗試獲取鎖,此時因為鎖已經被 Test 方法獲取而且並沒有釋放,所以會一直獲取不到鎖從而造成死鎖。

其實這種情況還有很多變形,比如說 lock(this)/lock("lockedString") 這種都是比較危險的,所以不推薦使用,我們使用上面的示例做一個變形,使用 lock("lockedString") 來測試一下。

public static void Test()
{
    lock ("Lock")
    {
        Task.Run(TestMethod1).Wait();
    }
}
private static void TestMethod1()
{
    lock ("Lock")
    {
        Console.WriteLine("xxx");
    }
}

這樣也會造成死鎖,因為 lock 的 string 實際上是同一個引用,字串池(string intern),所以類似於上面的示例,相當於是一個鎖,對於 lock(this) 也是類似的,所以通常 lock 是不推薦 lock(this)/lock("string") 這些寫法的,對於不同的資源要使用不同的 lock,這樣就可以避免上面這個示例的這種情況。

More

在 SQL Server 中會有一個獨立的死鎖檢測的程式,如果發生死鎖的情況,會有一個事務會被選擇為犧牲品來解決死鎖的問題。

在透過 Redis 實現分散式鎖的時候,通常會指定一個鎖的過期時間,過期時間通常是為了避免獲取鎖成功的系統突然當機導致鎖一直在鎖定狀態,從而導致其他服務獲取鎖的時候一直獲取失敗,除此之外,通常還會指定一個最大等待時間,如果別的服務獲取到鎖了,正在操作,那麼會等待鎖釋放,但是為了避免死鎖,如果長時間獲取不到鎖的話就會放棄獲取鎖,直接返回獲取鎖失敗。

原文地址:

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31559985/viewspace-2740514/,如需轉載,請註明出處,否則將追究法律責任。

相關文章