Lock deyimi - paylaşılan kaynağa özel erişim sağlayın
deyimi lock
belirli bir nesne için karşılıklı dışlama kilidini alır, bir deyim bloğu yürütür ve ardından kilidi serbest bırakır. Bir kilit tutulurken, kilidi tutan iş parçacığı kilidi tekrar alabilir ve serbest bırakılabilir. Diğer tüm iş parçacıklarının kilidi almaları engellenir ve kilit serbest bırakılana kadar bekler. deyimi, lock
gövdesini herhangi bir anda en fazla bir iş parçacığının yürütmesini sağlar.
deyimi lock
aşağıdaki formu alır:
lock (x)
{
// Your code...
}
Değişken x
türündeki System.Threading.Lock bir ifade veya başvuru türüdür. Derleme zamanında türünde System.Threading.Lockolduğu bilindiğindex
, tam olarak şunun eşdeğeridir:
using (x.EnterScope())
{
// Your code...
}
tarafından Lock.EnterScope() döndürülen nesnesi, ref struct
bir yöntemi içeren bir Dispose()
nesnesidir. Oluşturulan using
deyim, deyiminin gövdesiyle bir özel durum oluşturulsa bile kapsamın lock
serbest bırakılmasını sağlar.
Aksi takdirde, deyimi tam olarak şunun lock
eşdeğeridir:
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-finally
deyimi kullandığından, bir deyiminin gövdesinde lock
bir özel durum oluştursa bile kilit serbest bırakılır.
deyiminin await
gövdesinde lock
ifadeyi kullanamazsınız.
Yönergeler
.NET 9 ve C# 13'le başlayarak, en iyi performans için türün System.Threading.Lock ayrılmış bir nesne örneğini kilitleyin. Ayrıca, bilinen Lock
bir nesne başka bir türe yayınlanıp kilitlenirse derleyici bir uyarı yayınlar. Eski bir .NET ve C# sürümü kullanıyorsanız, başka bir amaç için kullanılmayan ayrılmış bir nesne örneğine kilitleyin. Kilitlenme veya kilit çekişmesiyle sonuçlanabileceği için farklı paylaşılan kaynaklar için aynı kilit nesnesi örneğini kullanmaktan kaçının. Özellikle, aşağıdaki örnekleri kilit nesneleri olarak kullanmaktan kaçının:
this
, arayanlar da kilitleyebileceğindenthis
.- Typeörnekleri, typeof işleci veya yansıma tarafından elde edilebileceğinden.
- dize değişmez değerleri de dahil olmak üzere dize örnekleri, bunlar interned olabilir.
Kilit çekişmesini azaltmak için bir kilidi mümkün olduğunca kısa süre tutun.
Örnek
Aşağıdaki örnek, ayrılmış balanceLock
bir Account
örneği kilitleyerek özel balance
alanına erişimi eşitleyen bir sınıfı tanımlar. Kilitleme için aynı örneği kullanmak, iki farklı iş parçacığının balance
veya Credit
yöntemlerini aynı anda çağırarak alanı güncelleştirememesini Debit
sağlar. Örnek, C# 13 ve yeni Lock
nesneyi kullanır. C# dosyasının eski bir sürümünü veya daha eski bir .NET kitaplığını kullanıyorsanız, örneğini kilitleyin object
.
using System;
using System.Threading.Tasks;
public class Account
{
// Use `object` in versions earlier than C# 13
private readonly System.Threading.Lock _balanceLock = new();
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 deyimi bölümüne bakın.