簡體   English   中英

C# 鎖定語句

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM