빌 와그너, ⌜More Effective C# 2판⌟, 김완섭 옮김, 한빛미디어, 2019
이 포스팅은 ⌜More Effective C# 2판⌟의 내용을 기반으로 작성되었습니다.
아이템 40: 동기화에는 lock()을 최우선으로 사용하라
스레드들은 공유 데이터에 대하여 동기화가 제대로 이루어져야 한다.
무결성 오류로 인한 문제를 피하려면 공유 데이터의 상태를 일관되게 유지해야 하고 '동기화 요소'를 사용해서 공유 데이터에 대한 접근을 제어해야 한다.
- 동기화 요소 : 특정 스레드가 임계영역(critical section)내에서 연산을 수행하는 동안 다른 스레드로 부터 이를 보호하는 역할을 수행한다.
lock()
- .NET 기본 클래스 라이브러리(BCL)의 기능
- 공유 데이터에 대한 접근을 안전하게 동기화해주는 다양한 기능 제공
- Monitor.Enter()와 Monitor.Exit()를 올바르게 사용했을 때와 유사한 코드를 생성
- 예외로부터 안전한 코드를 만들어줌
- Monitor에서 제공하는데 lock()에서 제공하지 않는 것
- lock()은 정적으로 범위를 구성할 수 밖에 없다.
- 임계 영역 진입, 빠져나오는 부분을 동적으로 구성할 수 없음
- Monitor.Enter()는 타임 아웃을 지원한다.
- lock() 사용 예
- lock() 안의 인자가 참조 타입이여야 한다.
public int TotalValue
{
get
{
lock(syncHandle) { return total; }
}
}
public void IncrementTotal()
{
lock (syncHadle) { total++};
}
- lock() 장점
- Monitor의 경우, Enter()와 Exit()는 따로 호출해야 하므로 서로 다른 객체의 락을 가져오거나 해제하는 실수를 저지르기 쉬운데, lock()은 그 과정이 필요 없어 미묘한 오류를 막아준다.
- 실수로 인한 예외로부터 안전한 코드를 자동으로 만들어준다.
- 대상 객체를 한번만 평가하므로, Monitor.Enter()와 Monitor.Exit() 보다 효율적인 코드를 생성해 준다.
System.Threading.Interlocked
대부분의 동기화 문제는 Interlocked가 제공하는 기능을 활용하면 해결할 수 있다.
그렇지 않은 경우라면 lock()을 가장 먼저 고려하자