3 回答

TA貢獻1829條經驗 獲得超7個贊
我認為由于某種原因,對于編譯器團隊而言,這既困難又不可能。
不,實施起來并非沒有困難或不可能,您自己實施的事實就證明了這一事實。相反,這是一個非常糟糕的主意,因此我們不允許這樣做,以防止您犯此錯誤。
在DisposeDisposable.Dispose中對Monitor.Exit的調用似乎無限期地(大部分時間)阻塞,導致死鎖,因為其他線程試圖獲取該鎖。我懷疑我的工作不可靠,而鎖語句中不允許使用await語句的原因與某種原因有關。
正確,您已經發(fā)現(xiàn)我們將其設為非法的原因。在鎖內部等待等待是產生死鎖的秘訣。
我敢肯定,您會明白為什么:在await將控制權返回給調用方與方法恢復之間的這段時間內,任意代碼都會運行。那個任意代碼可能會取出產生鎖順序倒置的鎖,從而導致死鎖。
更糟糕的是,代碼可能會在另一個線程上恢復(在高級方案中;通常您會在執(zhí)行等待的線程上再次接聽,但不一定),在這種情況下,解鎖將解鎖與所用線程不同的線程上的鎖開鎖。這是一個好主意嗎?沒有。
我注意到,出于相同的原因,對a進行yield return內部操作也是“最差的做法” lock。這樣做是合法的,但我希望我們將其定為非法。我們不會為“等待”犯同樣的錯誤。

TA貢獻1843條經驗 獲得超7個贊
使用SemaphoreSlim.WaitAsync方法。
await mySemaphoreSlim.WaitAsync();
try {
await Stuff();
} finally {
mySemaphoreSlim.Release();
}

TA貢獻1859條經驗 獲得超6個贊
基本上,這將是錯誤的事情。
有兩個方面,這可以實現(xiàn):
保持鎖,只在塊的末尾釋放它。
這是一個非常糟糕的主意,因為您不知道異步操作將花費多長時間。您只應在最短時間內握住鎖。這也可能是不可能的,因為線程擁有一個鎖,而不是一個方法-并且您甚至可能沒有在同一線程上執(zhí)行其余的異步方法(取決于任務調度程序)。
釋放等待中的鎖,并在等待返回時重新獲取它。
這違反了IMO最小原則,在IMO中,異步方法的行為應與等效的同步代碼盡可能接近-除非您Monitor.Wait在鎖塊中使用,否則您希望在該區(qū)塊的持續(xù)時間內擁有該鎖。
因此,這里基本上有兩個相互競爭的需求-您不應該在這里嘗試第一個,而如果您想采用第二種方法,則可以通過用await表達式分隔兩個分開的鎖塊來使代碼更清晰:
// Now it's clear where the locks will be acquired and released
lock (foo)
{
}
var result = await something;
lock (foo)
{
}
因此,通過禁止您等待鎖塊本身,該語言迫使您考慮自己真正想做的事情,并在編寫的代碼中使選擇更清晰。
- 3 回答
- 0 關注
- 3313 瀏覽
添加回答
舉報