如何寫(xiě)一段死鎖代碼
如何寫(xiě)一段死鎖代碼
Intro
上次介紹了如何寫(xiě)一段代碼造成 StackOverflow ,今天來(lái)玩一下,看如何寫(xiě)一段代碼造成死鎖
什么是死鎖
首先我們需要明確一下什么是死鎖,造成死鎖需要滿足哪些條件,知道這些就可以輕松寫(xiě)出一段死鎖代碼了
死鎖 是指兩個(gè)或兩個(gè)以上的進(jìn)程(線程)在執(zhí)行過(guò)程中,由于競(jìng)爭(zhēng)資源或者由于彼此通信而造成的一種阻塞的現(xiàn)象,若無(wú)外力作用,它們都將無(wú)法推進(jìn)下去。此時(shí)稱(chēng)系統(tǒng)處于死鎖 狀態(tài)或系統(tǒng)產(chǎn)生了死鎖,這些永遠(yuǎn)在互相等待的進(jìn)程稱(chēng)為死鎖 進(jìn)程(線程)。 ---- 百度百科
產(chǎn)生死鎖的必要條件:
-
互斥條件:進(jìn)程要求對(duì)所分配的資源進(jìn)行排它性控制,即在一段時(shí)間內(nèi)某資源僅為一進(jìn)程所占用。 -
請(qǐng)求和保持條件:當(dāng)進(jìn)程因請(qǐng)求資源而阻塞時(shí),對(duì)已獲得的資源保持不放。 -
不剝奪條件:進(jìn)程已獲得的資源在未使用完之前,不能剝奪,只能在使用完時(shí)由自己釋放。 -
環(huán)路等待條件:在發(fā)生死鎖時(shí),必然存在一個(gè)進(jìn)程--資源的環(huán)形鏈。
預(yù)防死鎖方法:
-
資源一次性分配:一次性分配所有資源,這樣就不會(huì)再有請(qǐng)求了:(破壞請(qǐng)求條件) -
只要有一個(gè)資源得不到分配,也不給這個(gè)進(jìn)程(線程)分配其他的資源:(破壞請(qǐng)保持條件) -
可剝奪資源:即當(dāng)某進(jìn)程獲得了部分資源,但得不到其它資源,則釋放已占有的資源(破壞不可剝奪條件) -
資源有序分配法:系統(tǒng)給每類(lèi)資源賦予一個(gè)編號(hào),每一個(gè)進(jìn)程按編號(hào)遞增的順序請(qǐng)求資源,釋放則相反(破壞環(huán)路等待條件)
.NET 中的死鎖
通常的死鎖的示例都是兩個(gè)鎖,多個(gè)資源導(dǎo)致的死鎖,你有沒(méi)有想過(guò)一個(gè)資源也會(huì)導(dǎo)致死鎖,如何使用一個(gè)鎖造成死鎖呢?思考一下再看下面的代碼
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這個(gè)方法中首先獲取鎖,獲取鎖成功之后調(diào)用另外一個(gè)線程去調(diào)用TestMethod1方法,而TestMethod1方法中會(huì)再次嘗試獲取鎖,此時(shí)因?yàn)殒i已經(jīng)被Test方法獲取而且并沒(méi)有釋放,所以會(huì)一直獲取不到鎖從而造成死鎖
其實(shí)這種情況還有很多變形,比如說(shuō) lock(this)/lock("lockedString") 這種都是比較危險(xiǎn)的,所以不推薦使用,我們使用上面的示例做一個(gè)變形,使用 lock("lockedString") 來(lái)測(cè)試一下
public static void Test()
{
lock ("Lock")
{
Task.Run(TestMethod1).Wait();
}
}
private static void TestMethod1()
{
lock ("Lock")
{
Console.WriteLine("xxx");
}
}
這樣也會(huì)造成死鎖,因?yàn)?lock 的 string 實(shí)際上是同一個(gè)引用,字符串池(string intern),所以類(lèi)似于上面的示例,相當(dāng)于是一個(gè)鎖,對(duì)于 lock(this) 也是類(lèi)似的,所以通常 lock 是不推薦 lock(this)/lock("string") 這些寫(xiě)法的,對(duì)于不同的資源要使用不同的 lock,這樣就可以避免上面這個(gè)示例的這種情況
More
使用鎖的一些注意事項(xiàng):
-
鎖要用來(lái)鎖定對(duì)應(yīng)的訪問(wèn)資源,不同的資源使用不同的鎖來(lái)訪問(wèn)限制 -
鎖盡可能使用這樣的格式 private readonly object _locker = new object();,是否使用static根據(jù)需要添加,多個(gè)資源有關(guān)聯(lián)時(shí),小心死鎖的情況,一次全部分配,任意一個(gè)資源分配失敗釋放另外一個(gè)鎖以避免死鎖 -
實(shí)現(xiàn)分布式鎖的時(shí)候指定最大嘗試時(shí)間,避免死鎖避免長(zhǎng)時(shí)間獲取不到鎖影響系統(tǒng)性能
在 SQL Server 中會(huì)有一個(gè)獨(dú)立的死鎖檢測(cè)的進(jìn)程,如果發(fā)生死鎖的情況,會(huì)有一個(gè)事務(wù)會(huì)被選擇為犧牲品來(lái)解決死鎖的問(wèn)題
在通過(guò) Redis 實(shí)現(xiàn)分布式鎖的時(shí)候,通常會(huì)指定一個(gè)鎖的過(guò)期時(shí)間,過(guò)期時(shí)間通常是為了避免獲取鎖成功的系統(tǒng)突然宕機(jī)導(dǎo)致鎖一直在鎖定狀態(tài),從而導(dǎo)致其他服務(wù)獲取鎖的時(shí)候一直獲取失敗,除此之外,通常還會(huì)指定一個(gè)最大等待時(shí)間,如果別的服務(wù)獲取到鎖了,正在操作,那么會(huì)等待鎖釋放,但是為了避免死鎖,如果長(zhǎng)時(shí)間獲取不到鎖的話就會(huì)放棄獲取鎖,直接返回獲取鎖失敗。
除此之外你還了解哪些使用鎖的注意事項(xiàng)和避免死鎖的常用方法呢,歡迎補(bǔ)充,如果文中有誤,歡迎指出,萬(wàn)分感謝。
Reference
-
https://baike.baidu.com/item/死鎖/2196938 -
https://blog.csdn.net/hd12370/article/details/82814348 -
https://github.com/WeihanLi/SamplesInPractice/blob/master/StupidSamples/DeadLockSample.cs
副業(yè)剛需,沒(méi)有人能拒絕這個(gè)網(wǎng)站!
微信錢(qián)包“免費(fèi)提現(xiàn)”的方法來(lái)了!
