뮤텍스란 하나의 프로세스가 임계 영역 내에 있다면 이 프로세스의 동작이 끝날 때가지 다른 프로세스가 임계 영역에 들어올 수 없도록 제한하는 알고리즘입니다.
공유 자원에 여러 스레드(프로세스)가 접근을 시도할 때 자원을 사용하는 스레드가 없다면 접근을 허용합니다. 접근을 허락 받은 스레드는 락
을 걸고 자원을 활용합니다. 이때 다른 스레드의 접근을 막는 락이 바로 Mutex Lock
입니다. 락이 걸린 상태에서 다른 스레드는 자원을 점유중인 스레드의 작업이 종료될 때 까지 해당 자원에 접근할 수 없습니다.
Spin Lock(Busy Waiting)
은 자신이 원하는 자원의 락
이 해제될 때 까지 while문
을 통해 지속적으로 자원에 접근을 시도
합니다.
반면에 뮤텍스는 당장 자원을 사용하지 못할 때 큐에서 sleep 상태로 대기
하게 됩니다. 자원을 사용한 스레드는 자원사용을 종료한 뒤 큐에서 대기중인 스레드를 깨우고
나갑니다. 이 때 sleep상태의 스레드가 다시 가동되기 위한 Context Switching
비용이 발생합니다.
만약 공유 자원을 사용하는데 소요되는 시간(대기시간)보다 Context Switching비용이 더 크다면 Mutex보다 SpinLock이 더 좋습니다. 멀티코어 환경에서는 이처럼 SpinLock이 더 좋은 상황이 발생할 수 있지만 싱글코어 환경에서는 항상 Mutex가 더 좋습니다. 그 이유는 SpinLock에서 락이 해제됐는지 확인하는 작업을 할 때마다 공유 자원에 접근 중인 스레드의 CPU를 뺏어와야 하기 때문입니다. (방이 비었는지 노크할때마다 안에 있는 사람이 작업을 진행하지 못하게 됩니다.)
세마포어는 뮤텍스의 공유자원이 여러 개
로 확장된 개념입니다. 세마포어는 count변수
와 대기 큐
를 가지고 있습니다. 보유중인 공유자원이 모두 사용 중이면 count변수를 음수로 변경
하고 대기 큐에 대기자를 적습니다. 어떤 스레드의 공유자원 사용이 끝나면 count변수를 1 증가
시키고 대기 큐의 스레드를 깨웁니다.
수도코드로 표현하면 다음과 같습니다.
semaphore s;
sem_init(s, num_of_shared_resources); // 초기화
sem_wait(s); // 대기
use_shared_resources(); // 공유자원 활용
sem_signal(s); // 자원 반납
int sem_wait(semaphore s){
s--;
if(s<0) wait;
}
int sem_signal(semaphore s){
s++;
if(exist_waiting) wake_process;
}
한마디로 세마포어는 공유자원의 접근을 제한하는 정수형 변수를 이용해서 공유 자원에 대한 접근을 제한하는 방법
을 말합니다.
뮤텍스
와 세마포어
는 공유 자원에 대한 접근을 제어하기 위한 동기화 매커니즘
입니다.
뮤텍스
는 임계 규역에 하나의 스레드만 진입이 가능합니다.
세마포어
는 임계 구역에 여러 스레드가 진입할 수 있습니다.