세마포
세마포 (Semaphores)
세마포는 뮤텍스 락보다 더 정교한 동기화 도구입니다. 세마포는 정수 변수로서 wait()
과 signal()
이라는 두 가지 원자적(atomic) 연산을 통해 접근할 수 있습니다. wait()
연산은 세마포 값을 감소시키고, signal()
연산은 세마포 값을 증가시킵니다.
기본 개념
세마포 S
는 정수 변수이며, 두 가지 원자적 연산을 통해서만 접근할 수 있습니다.
wait(S)
:S
가 0보다 작거나 같으면 대기.S
를 1 감소.
signal(S)
:S
를 1 증가.
세마포 유형:
계수 세마포 (Counting Semaphores):
값의 범위가 제한이 없습니다.
여러 리소스 인스턴스에 대한 접근을 제어하는 데 사용됩니다.
세마포는 가용 리소스의 개수로 초기화됩니다.
wait()
연산은 리소스를 사용하려고 할 때 호출되며, 세마포 값을 감소시킵니다.signal()
연산은 리소스 사용을 완료했을 때 호출되며, 세마포 값을 증가시킵니다.세마포 값이 0이 되면 모든 리소스가 사용 중이므로, 리소스를 요청하는 프로세스는 대기해야 합니다.
이진 세마포 (Binary Semaphores):
값은 0 또는 1로만 제한됩니다.
뮤텍스 락과 유사하게 작동하며, 상호 배제를 구현하는 데 사용될 수 있습니다.
wait(S)
를P()
연산으로,signal(S)
를V()
연산으로 부르기도 합니다.
세마포 구현
세마포 연산 wait()
과 signal()
은 원자적으로 실행되어야 합니다. 즉, 하나의 프로세스가 세마포 값을 변경하는 동안 다른 프로세스는 세마포 값을 변경할 수 없습니다. 다중 프로세서 환경에서는 일반적으로 compare and swap()
또는 test and set()
과 같은 하드웨어 명령어를 사용하여 원자성을 보장합니다.
바쁜 대기 없는 세마포 구현:
위에서 설명한 wait()과 signal() 구현은 바쁜 대기(busy waiting) 문제가 있습니다. 프로세스가 wait() 연산에서 대기해야 할 때, CPU를 낭비하면서 반복적으로 세마포 값을 확인합니다. 이를 해결하기 위해 세마포는 대기 중인 프로세스 목록(대기 큐)을 가질 수 있습니다.
wait(S)
연산:세마포 값
S
를 감소시킵니다.만약
S
가 음수가 되면, 현재 프로세스를 세마포의 대기 큐에 추가하고 이 프로세스를 블록(suspend)시켜 CPU에서 제거합니다.
signal(S)
연산:세마포 값
S
를 증가시킵니다.만약
S
가 0보다 크거나 같으면, 세마포의 대기 큐에 있는 블록된 프로세스 중 하나를 재개(wakeup)시킵니다.
이 구현은 바쁜 대기를 제거하지만, 문맥 교환(context switch)이라는 새로운 오버헤드를 도입합니다. 락이 짧은 시간 동안만 유지되는 경우(즉, 임계 구역이 짧은 경우), 바쁜 대기가 문맥 교환보다 효율적일 수 있습니다.
데드락 (Deadlock) 및 기아 (Starvation)
세마포를 부적절하게 사용하면 심각한 문제가 발생할 수 있습니다.
데드락 (Deadlock): 두 개 이상의 프로세스가 서로 상대방이 보유한 자원을 기다리며 무한히 대기하는 상황입니다. 예를 들어, 프로세스 P0와 P1이 두 개의 세마포(S, Q)를 사용하는 경우, P0가 S를 획득하고 P1이 Q를 획득한 후 서로 상대방의 세마포를 기다리면 데드락이 발생합니다.
기아 (Starvation): 세마포의 대기 큐가 FIFO(선입선출)가 아닌 우선순위 큐로 구현된 경우, 낮은 우선순위의 프로세스가 무한히 대기하는 기아 현상이 발생할 수 있습니다. 모든 프로세스가 언젠가는 큐에서 제거될 것임을 보장하는 노화(aging)와 같은 기법으로 해결할 수 있습니다.
우선순위 역전 (Priority Inversion): 높은 우선순위의 프로세스가 낮은 우선순위의 프로세스가 보유한 자원을 기다릴 때 발생합니다. 낮은 우선순위 프로세스가 자원을 해제하기 전까지는 높은 우선순위 프로세스가 실행되지 못합니다.
이러한 문제들을 관리하는 것은 세마포 기반 솔루션에서 매우 중요합니다.
Last updated