Lock deyimleri (C# Başvurusu)

lockİfade, belirli bir nesne için karşılıklı dışlama kilidi alır, bir ekstre bloğunu yürütür ve sonra kilidi serbest bırakır. Kilit tutulurken, kilidi tutan iş parçacığı kilidi yeniden alabilir ve serbest bırakabilir. Diğer herhangi bir iş parçacığının kilidi almak engellenir ve kilit serbest bırakılana kadar bekler.

lockİfade şu biçimdedir

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

x, başvuru türününbir ifadesidir. Tam olarak eşdeğerdir

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

Kod bir TRY kullandığından... finally bloğu, bir deyimin gövdesinde özel durum oluşturulursa bile kilit serbest bırakılır lock .

Bir deyimin gövdesinde await işlecini kullanamazsınız lock .

Yönergeler

İş parçacığı erişimini paylaşılan bir kaynağa eşitlediğinizde, ayrılmış bir nesne örneği üzerinde (örneğin, private readonly object balanceLock = new object(); ) veya kodun ilişkisiz parçaları tarafından kilit nesnesi olarak kullanılması olası bir örnek üzerinde kilit. Farklı paylaşılan kaynaklar için aynı kilit nesnesi örneğini kullanmaktan kaçının, çünkü kilitlenme veya kilitleme çekişmesine yol açabilir. Özellikle, Lock nesneleri olarak aşağıdakileri kullanmaktan kaçının:

  • this, çünkü çağıranlar bir kilit olarak kullanılıyor olabilir.
  • Typeörnekler, typeof işleci veya Reflection tarafından elde edilebilir.
  • dize sabit değerleri de dahil olmak üzere dize örnekleri birbirinebağlı olabilir.

Kilit çekişmesini azaltmak için olabildiğince kısa bir süre bekleyin.

Örnek

Aşağıdaki örnek, Account balance adanmış bir örnek üzerinde kilitleyerek özel alanına erişimi eşitleyen bir sınıfı tanımlar balanceLock . Kilitleme için aynı örneği kullanmak, alanın aynı anda balance veya yöntemlerini çağırmaya çalışan iki iş parçacığı tarafından aynı anda güncelleştirilememesini sağlar Debit Credit .

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)
    {
        if (amount < 0)
        {
            throw new ArgumentOutOfRangeException(nameof(amount), "The debit amount cannot be negative.");
        }

        decimal appliedAmount = 0;
        lock (balanceLock)
        {
            if (balance >= amount)
            {
                balance -= amount;
                appliedAmount = amount;
            }
        }
        return appliedAmount;
    }

    public void Credit(decimal amount)
    {
        if (amount < 0)
        {
            throw new ArgumentOutOfRangeException(nameof(amount), "The credit amount cannot be negative.");
        }

        lock (balanceLock)
        {
            balance += amount;
        }
    }

    public decimal GetBalance()
    {
        lock (balanceLock)
        {
            return balance;
        }
    }
}

class AccountTest
{
    static async Task Main()
    {
        var account = new Account(1000);
        var tasks = new Task[100];
        for (int i = 0; i < tasks.Length; i++)
        {
            tasks[i] = Task.Run(() => Update(account));
        }
        await Task.WhenAll(tasks);
        Console.WriteLine($"Account's balance is {account.GetBalance()}");
        // Output:
        // Account's balance is 2000
    }

    static void Update(Account account)
    {
        decimal[] amounts = { 0, 2, -3, 6, -2, -1, 8, -5, 11, -6 };
        foreach (var amount in amounts)
        {
            if (amount >= 0)
            {
                account.Credit(amount);
            }
            else
            {
                account.Debit(Math.Abs(amount));
            }
        }
    }
}

C# dili belirtimi

Daha fazla bilgi için C# dil belirtiminin kilit bildirimi bölümüne bakın.

Ayrıca bkz.