이 문은 lock 지정된 개체에 대한 상호 배제 잠금을 획득하고 문 블록을 실행한 다음 잠금을 해제합니다. 잠금이 유지되는 동안 잠금을 보유하는 스레드는 잠금을 다시 획득하고 해제할 수 있습니다. 다른 스레드는 잠금을 획득하지 못하도록 차단되고 잠금이 해제될 때까지 기다립니다. 이 문은 lock 한 번에 최대 하나의 스레드만 본문을 실행하도록 합니다.
이 문은 lock 다음과 같은 형식을 사용합니다.
lock (x)
{
// Your code...
}
변수 x 는 형식의 System.Threading.Lock 식이거나 참조 형식입니다. 컴파일 타임에 형식System.Threading.Lock으로 알려진 경우 x 다음과 정확히 동일합니다.
using (x.EnterScope())
{
// Your code...
}
반환되는 Lock.EnterScope() 개체는 메서드를 ref struct 포함하는 개체입니다 Dispose() . 생성된 using 문은 문 본문 lock 에 예외가 throw되더라도 범위가 해제되도록 합니다.
그렇지 않으면 문 lock 은 다음과 정확히 동일합니다.
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 내에서 예외가 throw되더라도 잠금이 해제됩니다.
문 본문 lock 에는 await 식을 사용할 수 없습니다.
지침
.NET 9 및 C# 13부터 최상의 성능을 위해 형식의 전용 개체 인스턴스를 System.Threading.Lock 잠급 수 있습니다. 또한 알려진 Lock 개체가 다른 형식으로 캐스팅되고 잠겨 있으면 컴파일러에서 경고를 발생합니다. 이전 버전의 .NET 및 C#을 사용하는 경우 다른 용도로 사용되지 않는 전용 개체 인스턴스를 잠급니다. 교착 상태 또는 잠금 경합이 발생할 수 있으므로 다른 공유 리소스에 동일한 잠금 개체 인스턴스를 사용하지 마세요. 특히 다음 인스턴스를 잠금 개체로 사용하지 않도록 합니다.
-
this- 호출자가 잠글this수도 있으므로 . - Type typeof 연산자 또는 리플렉션에서 가져올 수 있는 인스턴스입니다.
- 문자열 리터럴을 포함한 문자열 인스턴스는 인턴될 수 있습니다.
잠금 경합을 줄이기 위해 가능한 한 짧은 시간 동안 잠금을 유지합니다.
예시
다음 예제에서는 전용 balanceLock 인스턴스를 잠그고 프라이빗 balance 필드에 대한 액세스를 동기화하는 클래스를 정의 Account 합니다. 잠금에 동일한 인스턴스를 사용하면 두 스레드가 동시에 또는 Credit 메서드를 balance 호출 Debit 하여 필드를 업데이트할 수 없습니다. 샘플에서는 C# 13 및 새 Lock 개체를 사용합니다. 이전 버전의 C# 또는 이전 .NET 라이브러리를 사용하는 경우 인스턴스 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# 언어 사양
자세한 내용은 C# 언어 사양의 lock 문 섹션을 참조하세요.
참고하십시오
.NET