본문 바로가기
공부/게임서버

임계영역 (Critical Section)

by samosa 2024. 11. 10.

임계영역(critical section)은 여러 스레드가 동시에 접근할 때 문제가 발생할 수 있는 공유 자원(예: 변수, 데이터 구조 등)을 보호하기 위해 사용된다. 즉, 임계영역은 하나의 스레드가 해당 코드 블록을 실행할 때 다른 스레드가 접근하지 못하도록 하는 코드 영역이다. 이를 통해 데이터 무결성과 스레드 안전성을 보장할 수 있다.

임계영역의 필요성

스레드가 동시에 공유 자원에 접근할 때, 경합 조건(race condition)이 발생할 수 있다. 이러한 문제를 해결하기 위해 임계영역을 사용하여 하나의 스레드만 자원에 접근하도록 제한한다.

예시 코드 (C#)

다음은 lock 키워드를 사용하여 임계영역을 구현한 예시 코드이다.

using System;
using System.Threading;
using System.Threading.Tasks;

namespace CriticalSectionExample
{
    internal class Program
    {
        private static int number = 0;
        private static readonly object _lockObject = new object();

        private static void Increment()
        {
            for (int i = 0; i < 1000000; i++)
            {
                // 임계영역: 한 번에 하나의 스레드만 이 블록을 실행할 수 있다.
                lock (_lockObject)
                {
                    number++;
                }
            }
        }

        private static void Main(string[] args)
        {
            var t1 = new Task(Increment);
            var t2 = new Task(Increment);

            t1.Start();
            t2.Start();

            Task.WaitAll(t1, t2);

            Console.WriteLine($"Final value of number: {number}");
        }
    }
}

설명

  • lock 키워드: lock은 지정된 객체(_lockObject)를 사용하여 임계영역을 정의한다. lock 블록 내의 코드가 실행되는 동안 다른 스레드는 _lockObject를 사용한 lock 블록에 들어올 수 없다.
  • 공유 자원 보호: 이 예시에서 number는 공유 자원이며, lock을 사용하여 동시 접근으로 인한 경합 조건을 방지한다.

작동 원리

  1. 스레드 A가 lock(_lockObject)를 만나면 _lockObject를 잠근다.
  2. 스레드 B가 같은 lock(_lockObject)를 만나면, 스레드 A가 잠금을 해제할 때까지 기다린다.
  3. 스레드 A가 임계영역의 실행을 마치고 잠금을 해제하면, 스레드 B가 임계영역에 들어갈 수 있다.

이로써 여러 스레드가 동시에 number를 수정하지 않도록 하여 데이터 무결성을 유지할 수 있다.