반응형
스레드 제어에서 세마포어(Semaphore) 개념
세마포어는 멀티스레드 프로그래밍에서 리소스에 대한 접근을 제어하기 위한 도구입니다. 한정된 리소스(예: 데이터베이스 연결, 파일 처리 등)에 대해 동시에 접근 가능한 스레드 수를 제한하기 위해 사용됩니다.
세마포어(Semaphore)의 기본 개념
- 카운터 역할:
- 세마포어는 내부적으로 카운터를 가지고 있습니다.
- 이 카운터는 특정 리소스에 접근 가능한 최대 스레드 수를 나타냅니다.
- 예를 들어, 카운터가 3이면, 동시에 3개의 스레드만 리소스에 접근할 수 있습니다.
- 동작 원리:
- 스레드가 세마포어에 접근하면 카운터가 감소합니다.
- 작업이 끝나면 카운터가 증가합니다.
- 카운터가 0이면, 다른 스레드는 대기 상태가 됩니다.
- 비유:
- 세마포어를 주차장으로 생각할 수 있습니다.
- 주차장은 주차 가능한 최대 차량 수(카운터)를 설정합니다.
- 차량(스레드)이 들어오면 빈 자리가 줄어들고, 나가면 빈 자리가 늘어납니다.
- 빈 자리가 없으면(카운터가 0) 차량은 기다려야 합니다.
C#에서의 세마포어
1. Semaphore
C#에서 Semaphore는 .NET의 기본 제공 클래스입니다.
- 생성:
- initialCount: 현재 사용할 수 있는 리소스 개수.
- maximumCount: 최대 허용 리소스 개수.
Semaphore semaphore = new Semaphore(initialCount: 3, maximumCount: 3);
- 사용:
semaphore.WaitOne(); // 세마포어를 잠금(카운터 감소)
// 임계 구역 (리소스 사용 코드)
semaphore.Release(); // 세마포어 잠금 해제(카운터 증가)
- 특징:
- 프로세스 간 공유 가능: 네임드 세마포어를 사용하면 여러 프로세스에서 세마포어를 공유할 수 있습니다.
- 리소스가 다른 프로세스와 공유되어야 하는 경우 유리합니다.
2. SemaphoreSlim
SemaphoreSlim은 .NET에서 제공하는 경량화된 세마포어입니다.
- 생성:
- initialCount와 maxCount는 Semaphore와 동일하게 설정합니다.
SemaphoreSlim semaphoreSlim = new SemaphoreSlim(initialCount: 3, maxCount: 3);
- 사용:
await semaphoreSlim.WaitAsync(); // 비동기적으로 세마포어 잠금
// 임계 구역 (리소스 사용 코드)
semaphoreSlim.Release(); // 세마포어 잠금 해제
- 특징:
- 프로세스 내 사용에 최적화되어 있습니다.
- 비동기 지원(WaitAsync)을 기본적으로 제공하므로 비동기 작업에 적합합니다.
- 시스템 리소스를 적게 사용하므로 성능이 더 좋습니다.
Semaphore와 SemaphoreSlim의 차이점
특징 Semaphore SemaphoreSlim
리소스 공유 | 프로세스 간 공유 가능 | 프로세스 내에서만 사용 가능 |
비동기 지원 | 기본적으로 비동기 지원 없음 | WaitAsync로 비동기 지원 |
성능 | 상대적으로 무거움 | 경량화, 성능 우수 |
사용 시나리오 | 프로세스 간 리소스 동기화 필요 | 프로세스 내부 동기화 |
어떤 것을 언제 사용할까?
- Semaphore를 사용할 때:
- 프로세스 간 리소스를 공유하고자 할 때.
- 예: 두 개 이상의 애플리케이션에서 동일한 파일에 접근해야 하는 경우.
- SemaphoreSlim을 사용할 때:
- 단일 프로세스 내 동기화가 필요할 때.
- 비동기 작업을 사용할 때 (Task 기반의 비동기 프로그래밍).
- 시스템 리소스를 최적화하고 싶을 때.
예제 코드: SemaphoreSlim
아래는 SemaphoreSlim을 사용하여 동시에 3개의 스레드만 실행되도록 제한하는 예제입니다.
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static SemaphoreSlim semaphoreSlim = new SemaphoreSlim(3); // 최대 3개의 스레드 허용
static async Task Worker(int id)
{
Console.WriteLine($"Worker {id} 대기 중...");
await semaphoreSlim.WaitAsync(); // 세마포어 잠금
try
{
Console.WriteLine($"Worker {id} 시작");
await Task.Delay(2000); // 작업 시뮬레이션
Console.WriteLine($"Worker {id} 완료");
}
finally
{
semaphoreSlim.Release(); // 세마포어 해제
Console.WriteLine($"Worker {id} 종료 후 세마포어 해제");
}
}
static async Task Main(string[] args)
{
Task[] tasks = new Task[10];
for (int i = 0; i < 10; i++)
{
tasks[i] = Worker(i);
}
await Task.WhenAll(tasks);
Console.WriteLine("모든 작업 완료!");
}
}
요약
- Semaphore: 프로세스 간 리소스 동기화.
- SemaphoreSlim: 프로세스 내부의 경량화된 동기화, 비동기 작업에 적합.
- 선택 기준:
- 다른 프로세스와 리소스를 공유해야 한다면 Semaphore.
- 단일 프로세스 내에서 비동기 작업을 포함한 동기화가 필요하다면 SemaphoreSlim.
추가적인 질문이 있으면 언제든 물어보세요! 😊
반응형
'C# > 쓰레드' 카테고리의 다른 글
C# TPL: 태스크 생성 방식과 실행 흐름 완벽 이해 (1) | 2025.01.17 |
---|---|
C# `Thread`와 `ThreadPool`의 차이점 및 델리게이트 비동기 호출 이해 (16) | 2025.01.16 |
C# 스레드풀(Thread Pool): 개념, 사용법, 및 예제 코드 설명 (1) | 2025.01.16 |
C# SemaphoreSlim: 멀티스레드 리소스 접근 제어 예제와 설명 (1) | 2025.01.16 |
C# Mutex로 프로세스 단일 인스턴스 제어하기 (1) | 2025.01.16 |
원자적 작업(Atomic Operation): 동시성 문제 해결의 핵심 개념 (2) | 2025.01.16 |
스레드 우선순위와 CPU 시간 할당 이해하기 (2) | 2025.01.14 |
스레드_스레드 상태 조사_thread state (4) | 2025.01.06 |