공부/게임서버
AutoResetEvent
samosa
2024. 11. 14. 17:49
namespace ServerCore;
internal class Lock
{
AutoResetEvent _available = new AutoResetEvent(true); // true: available, false: not available
public void Enter()
{
_available.WaitOne(); // if available, continue, if not, wait
}
public void Leave()
{
_available.Set(); // set available to true
}
}
internal class Program
{
static int _num = 0;
static Lock _lock = new Lock();
public static void Thread_1()
{
for (int i = 0; i < 1000000; i++)
{
_lock.Enter();
_num++;
_lock.Leave();
}
}
public static void Thread_2()
{
for (int i = 0; i < 1000000; i++)
{
_lock.Enter();
_num--;
_lock.Leave();
}
}
private static void Main(string[] args)
{
var t1 = new Task(Thread_1);
var t2 = new Task(Thread_2);
t1.Start();
t2.Start();
Task.WaitAll(t1, t2);
Console.WriteLine(_num);
}
}
이 코드 예제는 AutoResetEvent
를 이용해 스레드 간의 동기화를 구현한 간단한 잠금 메커니즘이다. Lock
클래스는 스레드가 임계 구역에 진입하기 위해 사용할 수 있는 Enter
와 Leave
메서드를 제공한다. 이 예제를 기반으로 각 부분을 설명한다.
코드 설명
Lock
클래스
AutoResetEvent _available
: 잠금 상태를 관리하는AutoResetEvent
객체이다. 초기값true
는 리소스가 사용 가능함을 의미한다.Enter()
메서드:WaitOne()
을 호출해 스레드가_available
의 신호 상태를 대기한다._available
이 신호 상태(true
)일 경우,WaitOne()
은 즉시 반환되어 스레드가 임계 구역에 진입할 수 있다._available
의 상태가false
라면,WaitOne()
은_available
이 신호 상태가 될 때까지 대기한다.
Leave()
메서드:Set()
을 호출하여_available
의 상태를true
로 설정해 다음 대기 중인 스레드가 임계 구역에 진입할 수 있게 한다.
이 메커니즘은 한 번에 하나의 스레드만 임계 구역에 진입할 수 있도록 보장한다. 즉, AutoResetEvent
가 신호 상태를 자동으로 false
로 재설정하기 때문에 다른 스레드가 임계 구역에 진입할 때까지 대기하게 된다.
Program
클래스
_num
변수: 두 스레드가 공유하는 변수로, 동기화되지 않으면 경합 상태에서 불일치한 결과가 나올 수 있다.Thread_1()
:_lock.Enter()
로 잠금을 시도하고, 성공하면_num
을 증가시킨 후_lock.Leave()
로 잠금을 해제한다.
Thread_2()
:_lock.Enter()
로 잠금을 시도하고, 성공하면_num
을 감소시킨 후_lock.Leave()
로 잠금을 해제한다.
Main()
메서드:Thread_1
과Thread_2
를 각각 새로운Task
로 시작하고, 두 스레드의 완료를Task.WaitAll()
로 기다린다.- 프로그램 실행 후
_num
의 값을 출력한다.
동작 흐름
Thread_1
과Thread_2
는_lock.Enter()
를 호출해_available
의 상태를 확인한다.- 만약
_available
이true
라면WaitOne()
이 즉시 반환되고, 스레드는 임계 구역에 진입한다._available
은 자동으로false
로 바뀐다. - 스레드는 임계 구역에서
_num
을 변경한 후,_lock.Leave()
를 호출해_available.Set()
으로 상태를true
로 바꾸어 다음 스레드가 임계 구역에 진입할 수 있게 한다. - 두 스레드가 순차적으로 잠금을 획득하여
_num
을 변경하므로,AutoResetEvent
를 통해 다중 스레드 환경에서도 안전하게 동기화된다.
AutoResetEvent
의 역할
AutoResetEvent
는 한 번에 하나의 스레드만 임계 구역에 들어가도록 하는 역할을 한다. 스레드가 WaitOne()
을 호출해 _available
이 신호 상태(true
)라면 자동으로 _available
이 비신호 상태(false
)로 전환되어 다른 스레드는 대기 상태가 된다. Leave()
메서드에서 Set()
을 호출하면 _available
이 다시 true
로 전환되어 다음 대기 중인 스레드가 실행될 수 있다.
장점 및 단점
- 장점: 코드가 간단하며,
AutoResetEvent
를 통해 간단한 동기화 메커니즘을 쉽게 구현할 수 있다. - 단점: 스핀락에 비해 컨텍스트 스위칭 비용이 발생할 수 있어, 성능 면에서 제한이 있을 수 있다. 많은 스레드가 동시에 대기할 경우, 성능 저하가 발생할 수 있다.
이 코드는 스레드 동기화 문제를 다루는 기본적인 예제로, 다중 스레드 환경에서 공유 자원의 안전한 접근을 보장한다.