여러 스레드가 단일 개체의 속성 및 메서드를 호출할 수 있는 경우 이러한 호출을 동기화하는 것이 중요합니다. 그렇지 않으면 한 스레드가 다른 스레드가 수행하는 작업을 중단할 수 있으며 개체가 잘못된 상태로 남을 수 있습니다. 멤버가 이러한 중단으로부터 보호되는 클래스를 스레드로부터 안전한 클래스라고 합니다.
.NET 인스턴스 및 정적 멤버에 대한 액세스를 동기화하는 몇 가지 전략을 제공합니다.
동기화된 코드 영역입니다. 이 클래스에 Monitor 대한 클래스 또는 컴파일러 지원을 사용하여 필요한 코드 블록만 동기화하여 성능을 향상시킬 수 있습니다.
수동 동기화. .NET 클래스 라이브러리에서 제공하는 동기화 개체를 사용할 수 있습니다. 클래스 에 대한 설명이 포함된 동기화 기본 형식 개요를 Monitor 참조하세요.
동기화된 컨텍스트입니다. .NET Framework 애플리케이션에만 ContextBoundObject 개체에 대한 간단한 자동 동기화를 사용하도록 SynchronizationAttribute를 사용할 수 있습니다.
System.Collections.Concurrent 네임스페이스의 컬렉션 클래스입니다. 이러한 클래스는 기본 제공 동기화된 추가 및 제거 작업을 제공합니다. 자세한 내용은 Thread-Safe 컬렉션을 참조하세요.
공용 언어 런타임은 클래스가 요구 사항에 따라 다양한 방식으로 동기화될 수 있는 여러 범주로 분류되는 스레드 모델을 제공합니다. 다음 표에서는 지정된 동기화 범주를 사용하는 필드 및 메서드에 대해 제공되는 동기화 지원을 보여 줍니다.
| Category | 전역 필드 | 정적 필드 | 정적 메서드 | 인스턴스 필드 | 인스턴스 메서드 | 특정 코드 블록 |
|---|---|---|---|---|---|---|
| 동기화 없음 | 아니오 | 아니오 | 아니오 | 아니오 | 아니오 | 아니오 |
| 동기화된 컨텍스트 | 아니오 | 아니오 | 아니오 | Yes | Yes | 아니오 |
| 동기화된 코드 영역 | 아니오 | 아니오 | 표시된 경우에만 | 아니오 | 표시된 경우에만 | 표시된 경우에만 |
| 수동 동기화 | Manual | Manual | Manual | Manual | Manual | Manual |
동기화 없음
개체의 기본값입니다. 모든 스레드는 언제든지 모든 메서드 또는 필드에 액세스할 수 있습니다. 한 번에 하나의 스레드만 이러한 개체에 액세스해야 합니다.
수동 동기화
.NET 클래스 라이브러리는 스레드 동기화를 위한 다양한 클래스를 제공합니다. 동기화 기본 형식의 개요를 참조하세요.
동기화된 코드 영역
클래스 또는 컴파일러 키워드를 사용하여 Monitor 코드 블록, 인스턴스 메서드 및 정적 메서드를 동기화할 수 있습니다. 동기화된 정적 필드에 대한 지원은 없습니다.
Visual Basic과 C#은 모두 특정 언어 키워드, 즉 C#에서는 lock 문을 사용하고 Visual Basic에서는 SyncLock 문을 사용하여 코드 블록을 표시하도록 지원합니다. 스레드에서 코드를 실행하면 잠금을 획득하려고 시도합니다. 다른 스레드에서 잠금을 이미 획득한 경우 잠금을 사용할 수 있게 될 때까지 스레드가 차단됩니다. 스레드가 동기화된 코드 블록을 종료하면 스레드가 블록을 종료하는 방법에 관계없이 잠금이 해제됩니다.
메모
.NET 9 및 C# 13 이상에서는 lock 대상이 전용 System.Threading.Lock 인스턴스인 경우 lock 문은 Lock.EnterScope()를 사용하여 동기화된 영역을 만듭니다.
Visual Basic은 SyncLock에서 System.Threading.Lock를 지원하지 않으므로, 전용 private 참조 형식과 함께 SyncLock를 계속 사용하세요.
lock 대상이 Lock 인스턴스가 아니고, 모든 SyncLock 사용에 대해 컴파일러는 Monitor.Enter 및 Monitor.Exit를 사용합니다. 이 구현으로 인해 동기화된 지역에서 다른 Monitor 메서드를 계속 사용할 수 있습니다.
값이 MethodImplOptions.Synchronized인 MethodImplAttribute로 메서드를 데코레이션할 수도 있으며, 이는 Monitor 또는 컴파일러 키워드 중 하나를 사용하여 메서드 전체 본문을 잠그는 것과 동일한 효과를 냅니다.
Thread.Interrupt 는 동기화된 코드 영역에 대한 액세스를 기다리는 것과 같은 차단 작업에서 스레드를 중단하는 데 사용할 수 있습니다. Thread.Interrupt 는 다음과 같은 Thread.Sleep작업에서 스레드를 중단하는 데도 사용됩니다.
Important
static 메서드(Visual Basic의 경우 Shared 메서드)를 보호하기 위해 형식, 즉 C#의 typeof(MyType), Visual Basic의 GetType(MyType), 또는 C++의 MyType::typeid를 잠그지 마세요. 대신 프라이빗 정적 개체를 사용합니다. 마찬가지로 C#에서는 this를(을) 사용하여 인스턴스 메서드를 잠그지 마세요(Visual Basic에서는 Me). 대신 프라이빗 개체를 사용합니다. 클래스 또는 인스턴스는 사용자 고유의 코드가 아닌 다른 코드로 잠글 수 있으므로 교착 상태 또는 성능 문제가 발생할 수 있습니다.
컴파일러 지원
Visual Basic 및 C#은 모두 개체를 잠그는 데 Monitor.Enter 및 Monitor.Exit를 사용하는 언어 키워드를 지원합니다. Visual Basic SyncLock 문을 지원합니다. C#은 lock 문을 지원합니다.
두 경우 모두 코드 블록에서 예외가 발생하면 lock 또는 SyncLock으로 획득한 잠금은 자동으로 해제됩니다. C# 및 Visual Basic 컴파일러는 try의 시작 부분에 Monitor.Enter를 사용하여 /finally 블록을 내보내고 마지막 블록에서 Monitor.Exit를 내보냅니다. lock 또는 SyncLock 블록 내에서 예외가 발생하면 finally 핸들러가 실행되어 필요한 정리 작업을 수행할 수 있습니다.
동기화된 컨텍스트
.NET Framework 애플리케이션에서만 임의의 ContextBoundObject에서 SynchronizationAttribute를 사용하여 모든 인스턴스 메서드와 필드를 동기화할 수 있습니다. 동일한 컨텍스트 도메인의 모든 개체는 동일한 잠금을 공유합니다. 여러 스레드가 메서드 및 필드에 액세스할 수 있지만 한 번에 하나의 스레드만 허용됩니다.
참고하십시오
- SynchronizationAttribute
- 스레드 및 스레딩
- 동기화 기본 형식의 개요
- SyncLock 문
- lock 문
.NET