이번 글에서는 lock에 대해 알아보겠습니다. lock은 공유 리소스에 대한 단독 액세스를 보장하는 문입니다. 아래와 같이 공유된 리소스에 두 개의 쓰레드가 동시에 접근한다고 가정해봅시다.
static void Main(string[] args)
{
Thread thread1 = new Thread(() => Run());
Thread thread2 = new Thread(() => Run());
thread1.Start();
thread2.Start();
thread1.Join();
thread2.Join();
}
static int number = 0; // 두 개의 쓰레드에 공유된 자원
static void Run()
{
for (int i = 0; i < 100; i++)
{
int temp = number;
Console.WriteLine($"현재 숫자 : [{number}]");
number++;
Console.WriteLine($"1 증가 시킴");
if (temp + 1 == number)
Console.WriteLine($"1 증가 잘 됨");
else
Console.WriteLine($"???????? [{number}] ????????");
Thread.Sleep(10);
}
}
당연히 현재 값에서 1을 증가 시켰으니 temp + 1 == number 조건문은 무조건 참 일거라 생각이 됩니다. 실제로 실행하면 아래와 같이 실행됩니다.
두 개의 쓰레드가 동시에 number에 접근이 가능하다 보니 두 군데 동시에 number를 증가시키면 +2가 되기 때문입니다. 이 경우 두 개의 쓰레드라고 하더라도 특정 작업 구간에서는 서로 동시에 실행하지 못하게 상호 배제를 보장하게 하면 됩니다. 이 경우 lock을 사용합니다.
internal class Program
{
static void Main(string[] args)
{
Thread thread1 = new Thread(() => Run());
Thread thread2 = new Thread(() => Run());
thread1.Start();
thread2.Start();
thread1.Join();
thread2.Join();
}
static object lock_obj = new object(); // lock 개체
static int number = 0; // 두 개의 쓰레드에 공유된 자원
static void Run()
{
for (int i = 0; i < 100; i++)
{
lock (lock_obj) // lock_obj를 기준으로 임계영역 설정
{
int temp = number;
Console.WriteLine($"현재 숫자 : [{number}]");
number++;
Console.WriteLine($"1 증가 시킴");
if (temp + 1 == number)
Console.WriteLine($"1 증가 잘 됨");
else
Console.WriteLine($"???????? [{number}] ????????");
Thread.Sleep(10);
} // lock 블록 종료.
}
}
}
int는 lock에 사용할 수 없는 개체이므로 object lock_obj를 하나 만들어 lock을 시켜줍니다. 그러면 서로 다른 쓰레드는 lock 블록 안에서는 lock_obj 개체에 대한 상호 배제가 설정됩니다.
잘 실행되는 것을 볼 수 있습니다.
github : https://github.com/3001ssw/c_sharp/tree/main/basic/_lock

