뮤텍스와 세마포어는 자원의 동시성 이슈를 해결하기 위해, 하나의 자원에 여러개의 쓰레드가 동시에 접근하지 않도록 하는 방법이다.
뮤텍스
- 한번에 하나의 쓰레드만 자원에 접근 가능
- 자원은
잠금(Lock)
과해제(Unlock)
두 가지 상태만 가짐
class Mutex {
boolean locked = false // 초기 상태는 잠금 해제
Queue waitingThreads // 대기 중인 스레드 큐
method acquire() {
while (locked) { // 다른 스레드가 잠금 중이면
waitingThreads.add(currentThread) // 현재 스레드를 대기열에 추가
sleep() // 스레드를 대기 상태로
}
locked = true // 잠금 설정
}
method release() {
if (!waitingThreads.isEmpty()) { // 대기 중인 스레드가 있으면
thread = waitingThreads.remove() // 대기열에서 스레드 제거
wakeup(thread) // 해당 스레드 깨우기
}
locked = false // 잠금 해제
}
}
// 사용 예시
mutex = new Mutex()
process example() {
mutex.acquire()
// 임계 영역 (Critical Section)
// 공유 자원 접근
mutex.release()
}
세마포어
- 한번에 특정 카운트 만큼의 쓰레드가 자원에 접근 가능
- P(감소)와 V(증가) 연산을 통해 카운터를 조절
class Semaphore {
int value // 현재 사용 가능한 리소스 수
Queue waitingThreads // 대기 중인 스레드 큐
constructor(int initialValue) {
value = initialValue // 초기값 설정
}
method P() { // wait() 또는 acquire()
value = value - 1 // 리소스 하나 사용
if (value < 0) { // 사용 가능한 리소스가 없으면
waitingThreads.add(currentThread) // 현재 스레드를 대기열에 추가
sleep() // 스레드를 대기 상태로
}
}
method V() { // signal() 또는 release()
value = value + 1 // 리소스 하나 반환
if (!waitingThreads.isEmpty()) { // 대기 중인 스레드가 있으면
thread = waitingThreads.remove() // 대기열에서 스레드 제거
wakeup(thread) // 해당 스레드 깨우기
}
}
}
// 사용 예시
semaphore = new Semaphore(3) // 최대 3개의 스레드 동시 접근 가능
process example() {
semaphore.P()
// 임계 영역 (Critical Section)
// 공유 자원 접근
semaphore.V()
}