lock 문(C# 참조)lock statement (C# reference)

lock 문은 지정된 개체에 대한 상호 배제 잠금을 획득하여 명령문 블록을 실행한 다음, 잠금을 해제합니다.The lock statement acquires the mutual-exclusion lock for a given object, executes a statement block, and then releases the lock. 잠금이 유지되는 동안 잠금을 보유하는 스레드는 잠금을 다시 획득하고 해제할 수 있습니다.While a lock is held, the thread that holds the lock can again acquire and release the lock. 다른 스레드는 잠금을 획득할 수 없도록 차단되며 잠금이 해제될 때까지 대기합니다.Any other thread is blocked from acquiring the lock and waits until the lock is released.

lock 문이 형식입니다.The lock statement is of the form

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

여기서 x참조 형식의 식입니다.where x is an expression of a reference type. 정확히 다음과 같은 경우It's precisely equivalent to

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되더라도 잠금이 해제됩니다.Since the code uses a try...finally block, the lock is released even if an exception is thrown within the body of a lock statement.

lock 문의 본문에서 await 연산자를 사용할 수 없습니다.You can't use the await operator in the body of a lock statement.

설명Remarks

공유 리소스에 대한 스레드 액세스를 동기화하는 경우 전용 개체 인스턴스(예: private readonly object balanceLock = new object();) 또는 코드의 관련 없는 파트에서 잠금 개체로 사용되지 않을 가능성이 있는 다른 인스턴스를 잠급니다.When you synchronize thread access to a shared resource, lock on a dedicated object instance (for example, private readonly object balanceLock = new object();) or another instance that is unlikely to be used as a lock object by unrelated parts of the code. 교착 상태 또는 잠금 경합이 발생할 수 있으므로 다른 공유 리소스에 대해 동일한 잠금 개체 인스턴스를 사용하지 마세요.Avoid using the same lock object instance for different shared resources, as it might result in deadlock or lock contention. 특히 다음을 잠금 개체로 사용하지 마세요.In particular, avoid using the following as lock objects:

  • this(호출자가 잠금으로 사용할 수 있음).this, as it might be used by the callers as a lock.
  • Type 인스턴스(typeof 연산자 또는 리플렉션에서 획득할 수 있음).Type instances, as those might be obtained by the typeof operator or reflection.
  • 문자열 인스턴스(문자열 리터럴 포함)(인터닝될 수 있음).string instances, including string literals, as those might be interned.

예제Example

다음 예제에서는 전용 balanceLock 인스턴스에 잠금을 설정하여 해당 개인 balance 필드에 대한 액세스를 동기화하는 Account 클래스를 정의합니다.The following example defines an Account class that synchronizes access to its private balance field by locking on a dedicated balanceLock instance. 동일한 인스턴스를 잠금에 사용하면 Debit 또는 Credit 메서드를 동시에 호출하려는 두 스레드에 의해 balance 필드가 동시에 업데이트되지 않습니다.Using the same instance for locking ensures that the balance field cannot be updated simultaneously by two threads attempting to call the Debit or Credit methods simultaneously.

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# language specification

자세한 내용은 C# 언어 사양lock 문 섹션을 참조하세요.For more information, see The lock statement section of the C# language specification.

참조See also