AutoResetEvent는 키를 얻고 문을 닫는(다른 스레드 접근 불가) 처리를 자동으로 진행해준다.
class Lock
{
// 문을 닫는 행위를 자동으로 해준다. 커널 단위의 실행. SpinLock은 커널에 요청하지 않음
AutoResetEvent _available = new AutoResetEvent(true);
public void Acquire()
{
_available.WaitOne(); // 입장 시도
}
public void Release()
{
_available.Set(); // flag = true
}
}
class ThreadProgram
{
static int _num = 0;
static Lock _lock = new Lock();
static void Thread_1()
{
for(int i = 0; i < 10000; ++i)
{
_lock.Acquire();
_num++;
_lock.Release();
}
}
static void Thread_2()
{
for (int i = 0; i < 10000; ++i)
{
_lock.Acquire();
_num--;
_lock.Release();
}
}
static void Main(string[] args)
{
Task t1 = new Task(Thread_1);
Task t2 = new Task(Thread_2);
t1.Start();
t2.Start();
Task.WaitAll(t1, t2);
Console.WriteLine("num = " + _num);
}
}
ManualResetEvent 사용시, 정상적으로 동작하지 않는다.
로직이 원자성을 보장하지 않기 때문이다.
class Lock
{
// 문을 닫는 행위를 자동으로 해준다.
ManualResetEvent _available = new ManualResetEvent(true);
public void Acquire()
{
// 원자적 처리가 안 되서 문제가 발생한다.
_available.WaitOne(); // 입장 시도
_available.Reset(); // 문을 닫는다.
}
public void Release()
{
_available.Set(); // flag = true
}
}
뮤텍스 버전
class ThreadProgram
{
static int _num = 0;
static Mutex _lock = new Mutex();
static void Thread_1()
{
for(int i = 0; i < 10000; ++i)
{
_lock.WaitOne();
_num++;
_lock.ReleaseMutex();
}
}
static void Thread_2()
{
for (int i = 0; i < 10000; ++i)
{
_lock.WaitOne();
_num--;
_lock.ReleaseMutex();
}
}
static void Main(string[] args)
{
Task t1 = new Task(Thread_1);
Task t2 = new Task(Thread_2);
t1.Start();
t2.Start();
Task.WaitAll(t1, t2);
Console.WriteLine("num = " + _num);
}
}
SpinLock과 AutoResetEvent 방식의 차이
SpinLock 커널에 요청하는 동작이 아니지만, AutoResetEvent는 커널에 요청한다.
커널에 요청하는 동작이 더욱 많은 리소스를 소비한다.
'프로그래밍 > Game Dev' 카테고리의 다른 글
[Node.js] 간단한 멀티 슈팅게임 소스 분석 (0) | 2023.09.26 |
---|---|
[C#] Thread Local Storage (0) | 2023.08.28 |
[C#] SpinLock (0) | 2023.08.26 |
[C#] Interlocked (0) | 2023.08.26 |
[C#] MessagePack (0) | 2023.08.26 |
댓글