Monitor 키워드를 이용해 해당 행위를 끝날 때까지 작업을 보장해준다.
namespace SeverCore
{
class Program
{
static int number = 0;
static object _obj = new object();
static void Thread_1()
{
for (int i = 0; i < 100000; i++)
{
// 상호배제 Mutual Exclusive
Monitor.Enter(_obj); // 문을 잠구는 행위
number++;
Monitor.Exit(_obj); // 잠금을 풀어준다.
}
}
static void Thread_2()
{
for (int i = 0; i < 100000; i++)
{
Monitor.Enter(_obj);
number--;
Monitor.Exit(_obj);
}
}
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(number);
}
}
}
하지만 아래와 같이 Monitor.Enter()를 사용 후 Monitor.Exit()를 제대로 맞춰주지 않으면
데드락 (DeadLock) 현상이 발생한다.
for (int i = 0; i < 100000; i++)
{
// 상호배제 Mutual Exclusive
Monitor.Enter(_obj); // 문을 잠구는 행위
{
number++;
return;
}
Monitor.Exit(_obj); // 잠금을 풀어준다.
}
Monitor.Exit() 를 사용할 타이밍을 잡는 것이 조금 어려울 수 있다.
일반적인 상황에서는 이를 try ~ catch를 이용하여 해결한다.
for (int i = 0; i < 100000; i++)
{
// 상호배제 Mutual Exclusive
try
{
Monitor.Enter(_obj); // 문을 잠구는 행위
number++;
}
finally
{
Monitor.Exit(_obj); // 잠금을 풀어준다.
}
}
하지만 이도 번거롭다고 느낄 수 있기 때문에
lock이라는 키워드를 사용한다.
잠그고 여는 행위를 lock 키워드로 한번에 진행하는 것이다.
DeadLock을 조금이라도 줄일 수 있는 유용한 방법이다.
namespace SeverCore
{
class Program
{
static int number = 0;
static object _obj = new object();
static void Thread_1()
{
for (int i = 0; i < 100000; i++)
{
// 상호배제 Mutual Exclusive
lock (_obj)
{
number++;
}
}
}
static void Thread_2()
{
for (int i = 0; i < 100000; i++)
{
lock (_obj)
{
number--;
}
}
}
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(number);
}
}
}