2013-10-07 34 views
6

我最近讀this post from Eric Lippert regarding the lock implementation in c#和仍存在一些問題依然存在。鎖定語句 - 它總是釋放鎖嗎?

在4.0的實現如果一個線程終止或之前在finally塊中的Monitor.Exit(臨時)執行中出現任何跨線程異常 - 將在該保留對象的鎖?

有沒有發生異常,在這個層面上,留下對象仍然處於鎖定狀態的可能性?

+3

你可以試試這個自己。使用'Monitor.Enter'來鎖定另一個線程上的對象,調用'Thread.Abort'並查看另一個線程是否可以在該對象上輸入一個鎖。 – vcsjones

+1

Thread.Abort合法化堆棧中的異常,並在CLR終止線程之前執行finally塊。 – Gusdor

+1

Thread.Abort是唯一需要擔心跨線程異常的情況嗎? OutOfMemory或任何可以保持CLR進程正常運行的非託管異常,但只能在此精確點處終止此線程? – Rod

回答

14

在4.0實現中,如果在finally塊中的Monitor.Exit(temp)被執行之前線程中止或任何交叉線程異常發生 - 是否會保持鎖對象?

讓我們來看看這個代碼,因此它是清楚其他讀者:因爲它是基於一個錯誤的假設

bool lockWasTaken = false; 
var temp = obj; 
try 
{ 
    Monitor.Enter(temp, ref lockWasTaken); 
    { 
    body 
    } 
} 
finally 
{ 
    if (lockWasTaken) 
    { 
    // What if a thread abort happens right here? 
    Monitor.Exit(temp); 
    } 
} 

您的問題沒有回答的,即,該線程中止可發生在最後一塊的中間。

線程中止在finally塊的中間不可能發生。這僅僅是你爲什麼不應該試圖放棄一個線程的原因之一。整個線程可以在finally塊中運行,因此不會中止。

在這個級別發生異常是否有可能發生,使對象仍處於鎖定狀態?直到控制離開最後

第一個線程終止將被推遲。解鎖一個有效的鎖不會分配內存或拋出另一個異常。

9

閱讀了有關ThreadAbortException

當此異常升高時,運行結束線程

(這包括任何finally塊是目前前執行所有終於執行時Thread.Abort叫)

所以是的,鎖將被釋放。然而,這是否合乎要求是一個非常不同的問題 - 你不知道線程是否即將釋放鎖 - 它可能在任何地方,並且可能正在改變鎖正在保護的狀態 - 所以一如既往,建議是避免Thread.Abort

+0

你能看看我上面的評論嗎?我知道這是一個非常模糊的問題,但我想了解所有可能的情況 – Rod

+0

@Rod - OutOfMemory有點令人費解,因爲如果finally塊中的任何代碼想要分配,那麼顯然這將失敗。但是我曾經認爲'lock'語句的解鎖代碼屬於不太可能分配的代碼集合。我想不出任何解鎖失敗的情況,並且認爲你更有可能在兩週內贏得彩票,或者在兩臺獨立的機器上生成兩個相同的GUID。 –

+1

釋放一個有效的鎖並不會失敗,它不會分配內存。 –