728x90
이 글은 Inflearn - Rookiss : 게임서버 강의를 듣고 정리한 글입니다.

 

목차.

  1. 개요
  2. Interlocked 활용
  3. 정리

 

개요

 

Interlocked이 무엇인가에 대해 설명하기 앞서

다음 코드의 실행 결과로 어떤 값이 출력될까?

 

using System;
using System.Numerics;

namespace CSharp
{
    class Program {
        static int number = 0;

        static void Thread_1() 
        {
            for (int i = 0; i < 100000; i++)
                number++;
        }
        static void Thread_2()
        {
            for (int i = 0; i < 100000; i++)
                number--;
        }

        static void Main() 
        {
            Task t1 = new Task(Thread_1);
            Task t2 = new Task(Thread_2);
            t1.Start();
            t2.Start();

            Task.WaitAll(t1, t2);

            Console.WriteLine(number);
        }
    }
}

 

number를 각각 10만 번 더하고 빼주었기 때문에 0이 출력되어야 한다

 

하지만 실행을 해보면 결과는 그렇지 않다

 

랜덤-값이-출력
랜덤 값이 출력

무작위의 값이 출력되는 것을 볼 수 있다

 

왜 이런 결과가 나오는 걸까?

 

일반적으로 생각하는 작동방식

우리가 원하는 작업에 대한 결과물은 위 사진과 같을 것이다

 

number++이라는 작업을 시키면 하나의 스레드가 이를 실행해야 하는데

 

우리가 작성한 코드를 실행하면 

 

실제-작동방식
실제 작동방식

위와 같이 number++이 동시로 작동하기 때문에 0이라는 결과가 나오지 않은 것이다.

 

number++은 한 줄의 코드지만 내부적으로는 3줄의 코드라고 볼 수 있다.

 

int temp = num;
temp += 1;
num = temp

 

위 코드가 number++을 실행시켰을 일어나는 일이다.

 

그런데 스레드가 동시로 작동하여

위 코드가 동시에 작동한다고 하면 어떤 결과가 나올까?

 

number가  0이라고 가정해 보겠다.

 

Thread_1이 실행되었고 number가 1 증가하기 전 Thread_2가 실행되어 버리면 어떤 결과가 나올까?

 

순서가 정해져 있지 않아 불확실한 결과가 나오게 될 것이다.

 

그렇다면 코드를 원자적(atomic)으로 실행하기 위해서는 어떻게 해야 할까?

 

Interlocked 활용

 

using System;
using System.Numerics;

namespace CSharp
{
    class Program {
        static int number = 0;

        static void Thread_1() 
        {
            for (int i = 0; i < 100000; i++)
            {
                Interlocked.Increment(ref number);
            }
        }
        static void Thread_2()
        {
            for (int i = 0; i < 100000; i++)
            {
                Interlocked.Decrement(ref number);
            }
        }
        static void Main() 
        {
            Task t1 = new Task(Thread_1);
            Task t2 = new Task(Thread_2);
            t1.Start();
            t2.Start();

            Task.WaitAll(t1, t2);

            Console.WriteLine(number);
        }
    }
}

 

위 코드를 실행시켜보면 아까와는 달리 고정적으로 0이라는 결과가 출력된다.

 

Interlocked는 편리한 기능이지만 성능에서 손해를 볼 수 있다는 점 거의 정수 부분에서만 사용할 수 있다는 단점이 있다.

 

Interlocked의 특징은 해당 코드가 실행 중일 때는 절대로 끝나기 전까지 다른 코드가 실행되지 않는다는 특징이 있다.

이러한 이유로 위 코드의 순서가 보장되는 것이다.

 

Increment/Decrement 외에도
Exchange :
변수의 값을 다른 값으로 교환하고 이전 값을 반환

Compare and Swap : 변수의 현재 값과 지정된 값이 같은 경우에만 새 값을 설정

다음과 같은 기능들이 있습니다.

 

정리

 

이 글을 통해 Interlocked의 개념과 사용법에 대해 알아봤습니다.

Interlocked는 멀티스레드 프로그래밍에서 중요한 역할을 하며, 스레드 간의 동기화와 안전성을 보장하는 데 유용합니다.

 

 

728x90

+ Recent posts