Lock을 누가 점유하고 있다면?
1) 무작정 기다린다. => SpinLock
2) 나중에 다시 시도한다. (랜덤성) => 쓰레드가 자기 소유권을 포기 Context Switching
3) 운영체제의 도움을 받는다. => AutoResetEvent cf) Manual Reset Event
using System;
using System.Threading;
namespace SeverCore
{
class Lock
{
//bool <- 커널
AutoResetEvent _available = new AutoResetEvent(true); //문이 열린 상태
public void Acquire()
{
_available.WaitOne(); //입장 시도
//_available.Reset(); //위 코드에 포함
}
public void Release()
{
_available.Set(); //flag = true
}
}
class Program
{
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);
}
}
}
하지만 SpinLock 방식보다는 시간이 오래 걸린다.
using System;
using System.Threading;
namespace SeverCore
{
class Lock
{
//bool <- 커널
ManualResetEvent _available = new ManualResetEvent(true); //문이 열린 상태
public void Acquire()
{
_available.WaitOne(); //입장 시도
_available.Reset(); //문을 닫는다.
}
public void Release()
{
_available.Set(); //문을 열어준다.
}
}
class Program
{
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);
}
}
}

문을 열고 닫는 과정이 2개로 나뉘어져 있다.
즉 AutoResetEvent를 이용해 아래 과정을 하나로 묶었어야 한다.
_available.WaitOne(); //입장 시도
_available.Reset(); //문을 닫는다.
=> 한 번에 하나씩 입장하는 경우가 아니라
어떤 작업이 끝났으면 모든 쓰레드들이 다시 재가동 할 수 있게 할 때 사용할 수 있다.
AutoResetEvent와 같은 동작을 한다고 생각할 수 있다.
AutoResetEvent는 bool 값을 이용하지만 Mutex는 int를 이용할 수 있기 때문에
몇번 lock 했는지도 count 할 수 있다.
또한 ThreadId를 가지기에 어떤 부분에서 잘못됐는지 파악할 수 있다.
다만 추가 비용이 발생한다.
AutoResetEvent와 Mutex 모두 커널단에서 작동하기에 속도가 느리다.
using System;
using System.Threading;
namespace SeverCore
{
class Program
{
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);
}
}
}