(C#) 경합 조건과 원자성 (Interlocked)
포스트
취소

(C#) 경합 조건과 원자성 (Interlocked)

원자성이란?

여러 스레드가 존재할 때 특정 시점에서 어떠한 메소드를 두개 이상의 스레드가 동시에 호출하지 못한다.

멀티 스레드를 사용할 때 중요한 것 중에 하나가 바로 원장성이다. Interlocked는 이러한 원자성을 보장해주는 역할을 한다.

예를 들어 손님 1명과 직원 3명이 존재한다.

손님이 주문을 하여 콜라를 받아야할 상황일 때 직원 3명이 동시에 콜라를 전달해 준다면 이는 잘못된 방식일 것이다.

이러한 상황을 경합 조건이라 한다.

만약 여기에 원자성을 보장한다 가정하면 3명의 직원 중 제일 전달이 빠른 1명이 콜라를 전달하게 되고

나머지 직원을 콜라 전달에 대해 알게 되기 때문에 콜라 전달을 멈춘다.

💻 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
static int number = 0;

static void Thread_1()
{
    // 1000000번 number++
    for(int i=0; i<1000000; i++)
    {
        Interlocked.Increment(ref number);
    }
}

static void Thread_2()
{
    // 1000000번 number--
    for(int i=0; i<1000000; i++)
    {
        Interlocked.Decrement(ref 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);
}

number++ 과 Interlocked의 차이

  • number++ 같은 경우 변수를 가져와서 사용을 하기 때문에 다른 스레드보다 더 늦을 수 밖에 없다.
  • Interlocked는 number++ 같은 상황을 해결하기 위해 매개변수 값을 ref값(주소값)으로 받아 해당 주소로 가서 + / - 연산을 해준다. 이 덕분에 참조된 값은 몰라도 주소를 알기 때문에 변수를 가져오지 않고 주소로 바로 가서 연산을 수행할 수 있다.

Interlocked 값 확인

원자성이 보장된 Interlocked를 진행한 값을 확인하고 싶다면 number 값을 Debug해선 안된다.

왜냐하면 다른 스레드에서 이미 number라는 값을 사용하고 있기 때문이다.

이 때문에 연산된 값을 알고 싶다면 Interlocked의 리턴값을 받아야 한다.

O : int afterValue = Interlocked.Increment(ref number);
X : int afterValue = number;


💡 참고

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.