SpinLock에 이어서 또 다른 방법은 계속 기다리는 것이 아닌, 자신은 다른 일을 하다가 lock이 풀리게 되면 그때 알림을 받아서 lock을 획득하는 방식이 있다.
이 일을 AutoResetEvent가 하게되는데 철도 건널목에 비유를 하면 WaitOne이라는 차단기의 신호 상태에 따라 통과 여부를 판단할 수 있다.
코드에서는 처음에 true로 설정해서 쓰레드가 WaitOne을 만났을 때 바로 통과를 하고 Reset을 해서 문을 닫는다. 그리고 num++를 수행한 후에 Set을 해서 문을 열고 그 다음 쓰레드를 받도록 구현이 되어 있다.
참고로 ManualResetEvent와의 차이는 WaitOne의 상태를 따로 명시하지 않아도 Reset을 자동으로 해주느냐의 차이이다.
// SpinLock보다 오래걸림
class Lock
{
AutoResetEvent _available = new AutoResetEvent(true); // true로 초기화 : 열림
public void Acquire()
{
_available.WaitOne(); // 통과 시도. _available.Reset(), 즉 false로 해주는게 생략됨
}
public void Release()
{
_available.Set(); // true로
}
}
class Program
{
static int _num = 0;
static Lock _lock = new Lock();
static void Thread1()
{
for(int i=0; i<10000; i++)
{
_lock.Acquire();
_num++;
_lock.Release();
}
}
static void Thread2()
{
for(int i=0; i<10000; i++)
{
_lock.Acquire();
_num--;
_lock.Release();
}
}
static void Main(string[] args)
{
Task t1 = new Task(Thread1);
Task t2 = new Task(Thread2);
t1.Start();
t2.Start();
Task.WaitAll(t1, t2);
Console.WriteLine(_num);
}
}