세마포어 (Semaphore)

컴퓨터과학·AI
한 줄 정의: 정해진 개수의 자원을 여러 스레드가 나눠 쓸 수 있도록, 사용 가능한 자원의 개수를 세어가며 접근을 허용하거나 대기시키는 동기화 도구입니다.

쉽게 풀면

주차장을 떠올려 보세요. 주차 자리가 5개 있다면 최대 5대의 차만 동시에 들어갈 수 있고, 자리가 다 차면 남은 차들은 밖에서 기다려야 합니다. 차가 한 대 빠져나가면 대기 중인 차 한 대가 들어갈 수 있습니다. 세마포어는 이 주차장 관리인처럼, "지금 몇 자리가 남았는지"를 숫자로 세면서 그 숫자만큼만 스레드가 동시에 자원에 접근하도록 허용합니다. 자리가 1개뿐인 특수한 경우가 바로 뮤텍스이고, 세마포어는 그보다 더 일반적으로 여러 개의 자원을 동시에 여러 스레드에게 나눠줄 수 있다는 점이 다릅니다.

왜 중요한가

세마포어는 운영체제, 병렬·분산 시스템, 임베디드 소프트웨어 등에서 제한된 자원을 여러 실행 흐름이 안전하게 공유하도록 하는 가장 기본적인 동기화 도구 중 하나입니다. 멀티코어 환경이 보편화되면서 여러 스레드나 프로세스가 동시에 자원에 접근할 때 발생하는 경쟁 상태와 자원 고갈 문제를 다루는 시스템 논문에서, 세마포어는 새로운 동기화 기법과 성능을 비교하는 기준점으로 자주 등장합니다.

논문에서는 이렇게 쓰입니다

"데이터베이스 커넥션 풀은 카운팅 세마포어를 이용해 동시에 접속 가능한 커넥션 수를 최대 10개로 제한함으로써 서버 과부하를 방지하였다."

이 문장은 시스템 설계나 병렬 처리 성능을 다루는 논문에서, 제한된 자원을 여러 요청이 안전하게 나눠 쓰도록 설계했음을 설명하는 대목입니다. 세마포어는 스레드 풀, 커넥션 풀, 생산자-소비자 문제 등 동시성 제어가 필요한 시스템 논문에서 자주 등장합니다.

"임베디드 실시간 운영체제에서는 이진 세마포어를 이용해 인터럽트 서비스 루틴과 태스크 간의 이벤트 신호 전달을 구현함으로써 반응 지연을 최소화하였다."

임베디드 시스템 분야의 예문으로, 세마포어가 단순 자원 공유뿐 아니라 서로 다른 실행 문맥 간의 신호(signal) 전달 수단으로도 활용됨을 보여줍니다.

"생산자-소비자 큐를 구현할 때 빈 슬롯 수와 채워진 슬롯 수를 각각 세는 두 개의 세마포어를 사용해, 큐가 가득 찼을 때는 생산자를, 큐가 비었을 때는 소비자를 대기시키도록 설계하였다."

운영체제·병행프로그래밍 분야의 고전적 예문으로, 세마포어 두 개를 조합해 큐의 상태에 따라 생산자와 소비자를 각각 제어하는 대표적인 패턴을 보여줍니다.

조금 더 깊게 보면

세마포어는 내부적으로 정수 카운터와 대기 큐로 구성되며, 자원을 요청하는 wait(혹은 P) 연산과 반납하는 signal(혹은 V) 연산이 원자적으로 수행되어야 경쟁 상태를 막을 수 있습니다. 카운터 값이 1로 고정되어 상호배제만 제공하는 경우를 이진 세마포어라 부르고, 여러 개의 자원을 셀 수 있는 경우를 카운팅 세마포어라 구분합니다. 세마포어는 뮤텍스와 달리 소유권 개념이 없어 다른 스레드가 반납할 수 있다는 유연함이 있지만, 그만큼 잘못된 사용을 컴파일 시점이나 런타임에서 자동으로 잡아내기 어렵다는 점이 시스템 신뢰성 논문에서 종종 지적됩니다.

주의할 점

세마포어를 잘못 초기화하거나 자원을 반납(release)하는 코드를 빠뜨리면, 실제로는 자리가 남아 있는데도 스레드가 계속 대기하는 상태가 되어 교착 상태와 유사한 문제가 발생할 수 있습니다. 세마포어는 뮤텍스와 달리 자원을 획득한 스레드가 아닌 다른 스레드도 반납할 수 있어, 사용 규칙을 명확히 정해두지 않으면 버그를 찾기가 더 어려워질 수 있습니다.

관련 용어