1. 程式人生 > >lock 語句(C# 參考)

lock 語句(C# 參考)

lock 語句獲取給定物件的互斥 lock,執行語句 lock,然後釋放 lock。 持有 lock 時,持有 lock 的執行緒可以再次獲取並釋放 lock。 阻止任何其他執行緒獲取 lock 並等待釋放 lock。

lock 語句具有以下格式

C#

lock (x)
{
    // Your code...
}

其中 x 是引用型別的表示式。 它完全等同於

C#

object __lockObj = x;
bool __lockWasTaken = false;
try
{
    System.Threading.Monitor.Enter(__lockObj, ref __lockWasTaken);
    // Your code...
}
finally
{
    if (__lockWasTaken) System.Threading.Monitor.Exit(__lockObj);
}

由於該程式碼使用 try...finally 塊,即使在 lock 語句的正文中引發異常,也會釋放 lock。

在 lock 語句的正文中不能使用 await 關鍵字。

備註

當同步對共享資源的執行緒訪問時,請鎖定專用物件例項(例如,private readonly object balanceLock = new object();)或另一個不太可能被程式碼無關部分用作 lock 物件的例項。 避免對不同的共享資源使用相同的 lock 物件例項,因為這可能導致死鎖或鎖爭用。 具體而言,應避免使用

  • this(呼叫方可能將其用作 lock),
  • Type 例項(可以通過 typeof
     運算子或反射獲取),
  • 字串例項,包括字串文字,

用作 lock 物件。

示例

以下示例定義了一個 Account 類,該類通過鎖定專用的 balanceLock 例項來同步對其專用 balance 欄位的訪問。 使用相同的例項進行鎖定可確保嘗試同時呼叫 Debit 或 Credit方法的兩個執行緒無法同時更新 balance 欄位。

C#

using System;
using System.Threading.Tasks;

public class Account
{
    private readonly object balanceLock = new object();
    private decimal balance;

    public Account(decimal initialBalance)
    {
        balance = initialBalance;
    }

    public decimal Debit(decimal amount)
    {
        lock (balanceLock)
        {
            if (balance >= amount)
            {
                Console.WriteLine($"Balance before debit :{balance, 5}");
                Console.WriteLine($"Amount to remove     :{amount, 5}");
                balance = balance - amount;
                Console.WriteLine($"Balance after debit  :{balance, 5}");
                return amount;
            }
            else
            {
                return 0;
            }
        }
    }

    public void Credit(decimal amount)
    {
        lock (balanceLock)
        {
            Console.WriteLine($"Balance before credit:{balance, 5}");
            Console.WriteLine($"Amount to add        :{amount, 5}");
            balance = balance + amount;
            Console.WriteLine($"Balance after credit :{balance, 5}");
        }
    }
}

class AccountTest
{
    static void Main()
    {
        var account = new Account(1000);
        var tasks = new Task[100];
        for (int i = 0; i < tasks.Length; i++)
        {
            tasks[i] = Task.Run(() => RandomlyUpdate(account));
        }
        Task.WaitAll(tasks);
    }

    static void RandomlyUpdate(Account account)
    {
        var rnd = new Random();
        for (int i = 0; i < 10; i++)
        {
            var amount = rnd.Next(1, 100);
            bool doCredit = rnd.NextDouble() < 0.5;
            if (doCredit)
            {
                account.Credit(amount);
            }
            else
            {
                account.Debit(amount);
            }
        }
    }
}

C# 語言規範

有關詳細資訊,請參閱 C# 語言規範。 該語言規範是 C# 語法和用法的權威資料。