[英]C# Lock statements
當一個線程試圖進入臨界區並獲得鎖時,它實際上在做什么?
我問這個是因為我通常會創建一個 object (對象類型),它僅用於鎖定目的。 考慮以下內容:我想編寫一個接受集合的方法,以及一個 object,它將用作鎖定 object,因此該方法內的整個集合操作將在臨界區中聲明,該臨界區將被給定的 ZA8CFDE6331BD59EB66AC96F891C4 鎖定。
我應該使用“ref”傳遞鎖定 object 還是傳遞該 object 的參考副本就足夠了? 換句話說 - 由於 lock 語句僅與引用類型一起使用,該機制是檢查引用的 object的值,還是檢查指針的值? 因為顯然,當傳遞沒有“ref”的 object 時,我實際上得到了引用的副本,而不是引用本身。
這是您可以遵循的典型鎖定模式。 基本上,您可以創建一個鎖定 object 用於鎖定對您的關鍵部分的訪問(正如@Hans 所說,這並沒有保護您正在處理的 object - 它只是處理鎖定)。
class ThreadSafe
{
static readonly object _locker = new object();
static int _val1, _val2;
static void Go()
{
lock (_locker)
{
if (_val2 != 0) Console.WriteLine (_val1 / _val2);
_val2 = 0;
}
}
}
這個例子來自Joseph Albahari 的關於線程的在線書籍。 它很好地概述了創建lock
語句時發生的情況,以及一些關於如何最好地優化它的提示/技巧。 絕對強烈推薦閱讀。
根據 Albahari, lock
語句在 .NET 4 中再次轉換為:
bool lockTaken = false;
try
{
Monitor.Enter (_locker, ref lockTaken);
// Do your stuff...
}
finally { if (lockTaken) Monitor.Exit (_locker); }
它實際上比直接Monitor.Enter
更安全,然后在您的finally
中調用Monitor.Exit
,這就是為什么它被添加到 .NET 4 中的原因。
在不通過ref
的情況下鎖定object
就足夠了。 lock
的實際作用是,在塊的開頭調用Monitor.Enter ,在退出時調用Monitor.Exit 。
希望這可以幫助。
MSDN在這里說關於鎖
使用 Enter 獲取作為參數傳遞的 object 上的 Monitor。 如果另一個線程在 object 上執行了 Enter 但尚未執行相應的 Exit,則當前線程將阻塞,直到另一個線程釋放 object。 同一個線程在沒有阻塞的情況下多次調用 Enter 是合法的; 但是,在等待 object 的其他線程解除阻塞之前,必須調用相同數量的 Exit 調用。
這意味着它與引用或指針無關,它與實際的ref
有關
關於鎖內實際發生的事情,請參閱 這個問題的答案,其中說
“鎖定語句由 C# 翻譯成以下內容:”
var temp = obj;
Monitor.Enter(temp);
try
{
// body
}
finally
{
Monitor.Exit(temp);
}
我應該使用“ref”傳遞鎖定 object 還是傳遞該 object 的參考副本就足夠了?
可能兩者都沒有。 如果您有一些不是線程安全的資源,最好的選擇通常是僅從一個 class 直接訪問該資源,該 object 作為字段鎖定(或者您可以直接鎖定資源)。 如果您將鎖 object 傳遞給其他人,則很難確保代碼仍然可以正常工作,例如鎖定在應該完成的時候完成並且沒有死鎖。
但是如果你真的想通過鎖 object,你不需要使用ref
,正如其他人指出的那樣。 鎖定是在 object 的實例上完成的,而不是在包含對它的引用的變量上完成的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.