Lock
멀티쓰레드 환경에서 공유 자원의 동기화를 위해 사용. 즉, 여러 개의 쓰레드가 동시에 하나의 공유 자원을 접근할 때 데이터 충돌을 방지하기 위한 기능
Interlocked의 아쉬운점
앞서 설명한 Interlocked은 정수형 밖에 사용하지 못한다거나, 코드가 여러줄일 경우에는 굉장히 비효율적이다 라는 단점들이 발생한다. 단순히 정수를 더하거나, 빼는 것이 아닌 코드의 길이가 길 때, Lock을 사용할 수 있다.
static object _obj = new object();
static void Thread_1()
{
for (int i = 0; i < 1000000; i++)
{
Monitor.Enter(_obj);
number++;
Monitor.Exit(_obj)
}
}
static void Thread_2()
{
for (int i = 0; i < 1000000; i++)
{
Monitor.Enter(_obj);
number--;
Monitor.Exit(_obj);
}
}
위와 같이 사용할 수 있다. Monitor.Enter과 Monitor.Exit 사이에 실행되는 코드는 다른 쓰레드의 간섭을 받지 않고, 싱글 쓰레드와 같이 실행할 수 있다. 즉, 다른 쓰레드에서는 작업이 끝날 때까지 기다린다.
ex) Monitor.Enter : 1인용 화장실에서 문을 잠그는 행위.
ex) Monitor.Exit: 1인용 화장실에서 문을 여는 행위.
Dead Lock
static void Thread_1()
{
for (int i = 0; i < 1000000; i++)
{
Monitor.Enter(_obj);
number++;
return;
Monitor.Exit(_obj);
}
}
코드의 길이과 엄청 길어진다고 가정했을 때, 실수로 이와 같이 retrun을 하게 되면 프로그램은 멈춰버리고 만다. 다른 쓰레드에서는 쓰레드의 작업이 끝나기만을 영원히 기다리는 것이다. 이것을 Dead Lock이라고 한다.
ex) 1인용 화장실에서 문을 잠근채 잠들어버려서 줄을 서있는 사람이 계속 기다리는 것.
데드락을 줄일 수 있는 유용한 방법
static void Thread_1()
{
for (int i = 0; i < 1000000; i++)
{
lock(_obj)
{
number++;
}
}
}
static void Thread_2()
{
for (int i = 0; i < 1000000; i++)
{
lock (_obj)
{
number--;
}
}
}
Monitor.Enter과 Monitor.Exit은 앞서 확인한 것처럼 코드의 길이가 길면 실수할 여지가 있다. 그래서 이러한 데드락을 줄이기 위해 lock을 사용할 수 있다. lock도 내부 구현은 Monitor.Enter, Exit로 이루어져 있다. 편리한 lock으로 Monitor.Enter를 사용하는 경우는 거의 없고, 대부분의 경우 lock 키워드를 사용한다.
'서버 > 서버 이론' 카테고리의 다른 글
Lock 구현 (0) | 2025.03.29 |
---|---|
데드락 (DeadLock) (0) | 2025.03.28 |
InterLocked (0) | 2025.03.24 |
메모리 배리어 (0) | 2025.03.19 |
캐시 이론 (0) | 2025.03.18 |