반응형
이 코드는 **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(); // 세마포어 잠금 해제
- _semaphore.Wait():
- 스레드가 세마포어를 통해 데이터베이스에 접근하기 위해 대기합니다.
- 세마포어 카운터가 0이면, 스레드는 대기 상태에 들어갑니다.
- 데이터베이스 작업:
- 데이터베이스에 접근 권한을 얻은 스레드는 지정된 시간 동안 작업(Thread.Sleep)을 수행합니다.
- _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
결과 해석
- 처음에는 세마포어의 카운터가 4이므로 Thread 1 ~ Thread 4는 즉시 데이터베이스 접근을 허용받습니다.
- Thread 5와 Thread 6는 세마포어 카운터가 0이 되었기 때문에 대기 상태에 들어갑니다.
- Thread 1 작업이 끝나고 세마포어를 해제하면, Thread 5가 접근 권한을 얻습니다.
- 이후, 작업이 완료될 때마다 다른 대기 중인 스레드가 차례로 접근 권한을 얻습니다.
3. SemaphoreSlim의 동작 원리와 특징
- SemaphoreSlim의 역할:
- 세마포어는 제한된 리소스(여기서는 데이터베이스)에 대한 동시 접근을 제어합니다.
- SemaphoreSlim은 경량화된 세마포어로, 프로세스 내부의 스레드 동기화에 최적화되어 있습니다.
- 작동 방식:
- Wait 또는 WaitAsync: 세마포어 카운터를 감소시키며, 카운터가 0이면 대기 상태로 들어갑니다.
- Release: 세마포어 카운터를 증가시키며, 대기 중인 스레드를 깨웁니다.
- 주요 특징:
- SemaphoreSlim은 **비동기 작업(WaitAsync)**을 지원하여 비동기 프로그래밍에 적합합니다.
- SemaphoreSlim은 프로세스 내에서만 작동하므로, 프로세스 간 동기화가 필요할 경우 Semaphore를 사용해야 합니다.
4. SemaphoreSlim vs Semaphore
특징 Semaphore SemaphoreSlim
동기화 범위 | 프로세스 간 (네임드 세마포어) | 프로세스 내부 (스레드 간) |
비동기 지원 | 지원하지 않음 | WaitAsync로 비동기 지원 |
성능 | 상대적으로 무거움 | 경량화, 성능 우수 |
사용 사례 | 여러 프로세스에서 리소스를 공유 | 단일 프로세스 내부 동기화 |
5. 언제 SemaphoreSlim을 사용할까?
- 단일 프로세스에서 다수의 스레드가 제한된 리소스에 접근해야 할 때.
- 비동기 프로그래밍을 사용하는 경우(async/await).
- 경량화된 동기화를 필요로 하는 경우.
6. 요약
- 이 예제는 **SemaphoreSlim**을 사용해 동시에 4개의 스레드만 데이터베이스에 접근하도록 제한하는 방식으로 작동합니다.
- SemaphoreSlim은 경량화된 동기화 도구로, 단일 프로세스에서 스레드 간 리소스 접근을 제어하는 데 매우 적합합니다.
- 동시성 제어와 리소스 관리가 중요할 때 SemaphoreSlim을 사용하는 것을 고려하세요!
추가적인 설명이 필요하면 말씀해주세요! 😊
반응형
'C# > 쓰레드' 카테고리의 다른 글
C# Task 기본 동작과 스레드 실행 시나리오 이해 (12) | 2025.01.17 |
---|---|
C# TPL: 태스크 생성 방식과 실행 흐름 완벽 이해 (1) | 2025.01.17 |
C# `Thread`와 `ThreadPool`의 차이점 및 델리게이트 비동기 호출 이해 (16) | 2025.01.16 |
C# 스레드풀(Thread Pool): 개념, 사용법, 및 예제 코드 설명 (1) | 2025.01.16 |
C# 스레드 제어: Semaphore와 SemaphoreSlim의 차이와 사용법 (1) | 2025.01.16 |
C# Mutex로 프로세스 단일 인스턴스 제어하기 (1) | 2025.01.16 |
원자적 작업(Atomic Operation): 동시성 문제 해결의 핵심 개념 (2) | 2025.01.16 |
스레드 우선순위와 CPU 시간 할당 이해하기 (2) | 2025.01.14 |