본문 바로가기
C#/쓰레드

C# SemaphoreSlim: 멀티스레드 리소스 접근 제어 예제와 설명

by 공부봇 2025. 1. 16.
반응형

이 코드는 **SemaphoreSlim**을 사용하여 동시에 최대 4개의 스레드만 데이터베이스에 접근할 수 있도록 제한하는 예제입니다. 아래에서 코드 동작을 단계별로 분석하고, 이를 바탕으로 SemaphoreSlim의 동작 원리와 특성을 설명하겠습니다.

    internal class Program
    {
        static SemaphoreSlim _semaphore = new SemaphoreSlim(4);

        static void AccessDatabase(string name, int seconds)
        {
            Console.WriteLine("{0} waits to access a database", name);
            _semaphore.Wait();

            Console.WriteLine("{0} was granted an access to a database", name);
            Thread.Sleep(TimeSpan.FromSeconds(seconds));

            Console.WriteLine("{0} is completed", name);
            _semaphore.Release();
        }


        static void Main(string[] args)
        {
            for (int i = 1; i <= 6; i++)
            {
                string threadName = "Thread " + i;
                int secondsToWait = 2 + 2 * i;
                var t = new Thread(() => AccessDatabase(threadName, secondsToWait));
                t.Start();
            }
        }
    }

 

1. 코드 구조 및 주요 부분

1.1 SemaphoreSlim 초기화

static SemaphoreSlim _semaphore = new SemaphoreSlim(4);
  • SemaphoreSlim 생성자: SemaphoreSlim의 첫 번째 매개변수로 초기 카운트를 설정합니다.
  • 여기서는 초기 카운트를 4로 설정했으므로, 동시에 4개의 스레드만 리소스(데이터베이스)에 접근할 수 있습니다.

1.2 스레드 생성 및 실행

for (int i = 1; i <= 6; i++)
{
    string threadName = "Thread " + i;
    int secondsToWait = 2 + 2 * i;
    var t = new Thread(() => AccessDatabase(threadName, secondsToWait));
    t.Start();
}
  • 6개의 스레드를 생성하고 시작합니다.
  • 각 스레드에는 고유한 이름(Thread 1 ~ Thread 6)과 데이터베이스 작업 시간이 주어집니다.
    • 작업 시간은 2 + 2 * i로 계산되며, 스레드마다 다릅니다.

1.3 데이터베이스 접근 제어

_semaphore.Wait(); // 세마포어 잠금
Console.WriteLine("{0} was granted an access to a database", name);
Thread.Sleep(TimeSpan.FromSeconds(seconds)); // 데이터베이스 작업 수행
Console.WriteLine("{0} is completed", name);
_semaphore.Release(); // 세마포어 잠금 해제
  1. _semaphore.Wait():
    • 스레드가 세마포어를 통해 데이터베이스에 접근하기 위해 대기합니다.
    • 세마포어 카운터가 0이면, 스레드는 대기 상태에 들어갑니다.
  2. 데이터베이스 작업:
    • 데이터베이스에 접근 권한을 얻은 스레드는 지정된 시간 동안 작업(Thread.Sleep)을 수행합니다.
  3. _semaphore.Release():
    • 데이터베이스 작업이 끝난 스레드는 세마포어 잠금을 해제하며, 카운터를 증가시킵니다.
    • 대기 중인 스레드가 있다면, 카운터가 증가하면서 접근 권한을 얻게 됩니다.

2. 실행 결과 예상

출력은 실행 환경에 따라 약간 달라질 수 있지만, 주요 흐름은 동일합니다.

예시 출력

Thread 1 waits to access a database
Thread 2 waits to access a database
Thread 3 waits to access a database
Thread 4 waits to access a database
Thread 1 was granted an access to a database
Thread 2 was granted an access to a database
Thread 3 was granted an access to a database
Thread 4 was granted an access to a database
Thread 5 waits to access a database
Thread 6 waits to access a database
Thread 1 is completed
Thread 5 was granted an access to a database
Thread 2 is completed
Thread 6 was granted an access to a database
Thread 3 is completed
Thread 4 is completed
Thread 5 is completed
Thread 6 is completed

결과 해석

  1. 처음에는 세마포어의 카운터가 4이므로 Thread 1 ~ Thread 4는 즉시 데이터베이스 접근을 허용받습니다.
  2. Thread 5Thread 6는 세마포어 카운터가 0이 되었기 때문에 대기 상태에 들어갑니다.
  3. Thread 1 작업이 끝나고 세마포어를 해제하면, Thread 5가 접근 권한을 얻습니다.
  4. 이후, 작업이 완료될 때마다 다른 대기 중인 스레드가 차례로 접근 권한을 얻습니다.

3. SemaphoreSlim의 동작 원리와 특징

  1. SemaphoreSlim의 역할:
    • 세마포어는 제한된 리소스(여기서는 데이터베이스)에 대한 동시 접근을 제어합니다.
    • SemaphoreSlim은 경량화된 세마포어로, 프로세스 내부의 스레드 동기화에 최적화되어 있습니다.
  2. 작동 방식:
    • Wait 또는 WaitAsync: 세마포어 카운터를 감소시키며, 카운터가 0이면 대기 상태로 들어갑니다.
    • Release: 세마포어 카운터를 증가시키며, 대기 중인 스레드를 깨웁니다.
  3. 주요 특징:
    • SemaphoreSlim은 **비동기 작업(WaitAsync)**을 지원하여 비동기 프로그래밍에 적합합니다.
    • SemaphoreSlim은 프로세스 내에서만 작동하므로, 프로세스 간 동기화가 필요할 경우 Semaphore를 사용해야 합니다.

4. SemaphoreSlim vs Semaphore

특징 Semaphore SemaphoreSlim

동기화 범위 프로세스 간 (네임드 세마포어) 프로세스 내부 (스레드 간)
비동기 지원 지원하지 않음 WaitAsync로 비동기 지원
성능 상대적으로 무거움 경량화, 성능 우수
사용 사례 여러 프로세스에서 리소스를 공유 단일 프로세스 내부 동기화

5. 언제 SemaphoreSlim을 사용할까?

  • 단일 프로세스에서 다수의 스레드가 제한된 리소스에 접근해야 할 때.
  • 비동기 프로그래밍을 사용하는 경우(async/await).
  • 경량화된 동기화를 필요로 하는 경우.

6. 요약

  • 이 예제는 **SemaphoreSlim**을 사용해 동시에 4개의 스레드만 데이터베이스에 접근하도록 제한하는 방식으로 작동합니다.
  • SemaphoreSlim은 경량화된 동기화 도구로, 단일 프로세스에서 스레드 간 리소스 접근을 제어하는 데 매우 적합합니다.
  • 동시성 제어와 리소스 관리가 중요할 때 SemaphoreSlim을 사용하는 것을 고려하세요!

추가적인 설명이 필요하면 말씀해주세요! 😊

반응형