세마포어
멀티스레드나 멀티프로세스 환경에서는 여러 실행 흐름이 동시에 하나의 공유 자원에 접근할 수 있기 때문에, 예상치 못한 충돌이나 오류가 발생할 수 있다.
이를 방지하기 위해 등장한 동기화 도구 중 가장 기본적이면서 강력한 것이 바로 세마포어(Semaphore)이다.
세마포어는 크게 카운팅 세마포어와 이진 세마포어로 나뉘며, 이 글에서는 두 종류를 각각 개념부터 동작 방식, 예외 사항까지 정리한다.
1. 범용 세마포어 (카운팅 세마포어)
개념
카운팅 세마포어는 정수 값을 가지는 동기화 객체로, 여러 개의 동일한 공유 자원을 보호할 때 사용된다.
세마포어의 값은 현재 사용 가능한 자원의 수를 의미하며, 프로세스나 스레드가 자원을 사용할 때는 값을 감소시키고, 반납할 때는 값을 증가시킨다.
연산
- 초기화: 자원의 개수만큼 0 이상의 값으로 초기화
예를 들어 3개의 프린터를 보호하려면 세마포어를 3으로 초기화한다 - wait() 연산 (P 연산)
세마포어 값을 1 감소
감소 후 값이 음수이면, 해당 프로세스는 블록되어 대기열에 들어간다 - signal() 연산 (V 연산)
세마포어 값을 1 증가
만약 대기 중인 프로세스가 있다면 하나를 깨운다
값의 의미
- 양수: 자원이 남아 있어 바로 사용 가능
- 0: 자원이 모두 사용 중이며, 새로운 접근은 대기해야 함
- 음수: 절댓값만큼의 프로세스가 대기 중
큐 정책
- 강성 세마포어: 가장 오래 대기한 프로세스를 먼저 깨운다 (FIFO)
- 약성 세마포어: 스케줄러가 자유롭게 선택
특징
- 자원이 0이 아닐 경우 블록되지 않고 수행된다
- signal은 블록된 프로세스가 없더라도 항상 값을 증가시킨다
- wait과 signal은 반드시 원자적이어야 하며, 수행 중 끼어들 수 없다
- 카운팅 세마포어는 동시에 여러 프로세스가 접근 가능하므로, 다중 자원 보호에 적합하다
2. 이진 세마포어 (Binary Semaphore)
개념
이진 세마포어는 0 또는 1의 값만을 가지는 세마포어로, 오직 하나의 자원만을 보호할 때 사용된다.
기본적인 구조와 동작 방식은 카운팅 세마포어와 같지만, 값이 1 이상 되지 않도록 제한된다.
연산
- 초기화: 1로 초기화하여 하나의 자원이 존재함을 표시
- wait()
세마포어 값이 1이면 0으로 만들고 진입
세마포어 값이 0이면 해당 프로세스는 블록됨 - signal()
대기 중인 프로세스가 있으면 그 프로세스를 깨움
없으면 세마포어 값을 1로 설정
특징
- 하나의 자원을 보호하기 위한 동기화 기법
- 뮤텍스와 매우 유사한 구조를 가지지만, 소유 개념이 없다는 차이가 있다
- 카운팅 세마포어보다 구현이 간단하고 가벼운 대신, 동시 접근이 필요한 경우에는 사용할 수 없다
세마포어 요약 비교
항목 | 카운팅 세마포어 | 이진 세마포어 |
값의 범위 | 0 이상 | 0 또는 1 |
자원 수 | 여러 개 | 1개 |
사용 목적 | 다중 자원 보호 | 단일 자원 보호 |
구현 복잡도 | 다소 복잡 | 간단 |
사용 예시 | 프린터 여러 대, 연결 제한 | 임계 영역 보호, 플래그 제어 |
세마포어와 뮤텍스의 차이
항목 | 세마포어 | 뮤텍스 |
자원 수 | 여러 개 자원 (카운팅 가능) | 하나의 자원 (단일 보호) |
소유 개념 | 없음 (누구나 wait, signal 가능) | 있음 (lock한 스레드만 unlock 가능) |
사용 범위 | 프로세스 간, 스레드 간 모두 가능 | 주로 스레드 간 |
연산 이름 | wait(), signal() | lock(), unlock() |
용도 | 접근 횟수 제어, 흐름 제어 | 상호 배제 (Mutual Exclusion) |
구현 복잡도 | 비교적 복잡 | 상대적으로 간단 |
이진 세마포어와 뮤텍스의 차이
이진 세마포어와 뮤텍스는 모두 한 번에 하나의 스레드만 공유 자원에 접근하게 만드는 동기화 도구라는 점에서 기능적으로 유사해 보인다.
하지만 두 도구 사이에는 중요한 차이가 있다.
- 이진 세마포어는 소유 개념이 없다.
자원을 점유한 스레드가 아니더라도 누구나 signal()을 호출해 세마포어 값을 1로 만들어 다른 스레드를 깨울 수 있다.
이로 인해 보다 범용적이며, 단순한 순서 제어나 동기화에도 사용된다. - 뮤텍스는 소유 개념이 있다.
lock()을 호출해 뮤텍스를 획득한 해당 스레드만이 unlock()을 호출할 수 있다.
이로 인해 명확한 소유권 기반의 상호 배제가 가능하며, 임계영역 보호에 특화된 도구이다.
결론적으로,
이진 세마포어는 더 범용적인 동기화 용도에 적합하며,
뮤텍스는 소유 개념을 통해 더 엄격한 상호 배제를 보장한다.
'OS' 카테고리의 다른 글
프로그램은 어떻게 실행되는가 (0) | 2025.06.24 |
---|---|
스핀락(Spin Lock) (3) | 2025.06.24 |
뮤텍스(Mutex) (0) | 2025.06.24 |
멀티쓰레드 환경에서 생길 수 있는 문제들 (0) | 2025.06.24 |
다양한 OS 스케줄링 기법 (0) | 2025.06.24 |