하드웨어 명령어들은 복잡하기 때문에 성능과 프로세스 실행에 있어서 문제를 일으킬 수 있습니다. 따라서 커널 라이브러리를 통해 기능을 제공합니다. 그 중 가장 간단한 방법이 Mutex lock 입니다.
acquire()
release()
위 두 함수는 atomic 한 명령어 입니다.
do {
acquire(lock);
// critical section
release(lock);
// remainder section
} while (true);
acquire() {
while (!available) ; // busy-waiting
available = false;
}
release() {
available = true;
}
이런식으로 동작합니다. 이 때, acquire()
에서 busy-waiting이 발생합니다. (CPU 시간은 사용하는데, 무의미하고 무조건적인 대기로 CPU 낭비를 일으키는 시간)
Mutex는 두 스레드 간 경쟁만을 지원하는 반면, Semaphore는 여러 스레드 간 경쟁도 지원할 수 있습니다. 2개의 atomic operation 을 이용합니다.
wait()
: 사용 대기!signal()
: 사용 끝!구현은 다음처럼 이루어집니다.
wait(S) {
while (S <= 0) ; //busy-waiting
S--;
}
signal(S) {
S++;
}
범용성이 좋아 많이 사용됩니다. semaphore 에는 2가지 종류가 있습니다.
CS 시작 전에 wait()
, 끝나고 signal()
을 호출하므로써 해결할 수 있지만, 여전히 busy-waiting이 존재합니다.
2가지 operation 이 추가됩니다.
sleep()
: 해당 프로세스를 waiting queue 로 보냅니다.wakeup()
: waiting queue에 있는 프로세스 하나를 ready queue 로 보냅니다.이를 이용하여 구현하면
이러한 모습입니다. 하지만 문제점이 발생합니다. 오히려 CS를 더 만들어버리는 상황이 발생합니다. 따라서 일반적으로는 busy-waiting이 발생해도 그대로 두는 편입니다. 하지만, CS를 지나치게 오래 점유하는 프로세스와 협업하는 경우에는 busy-waiting₩이 비효율적이므로 다른 대책이 필요합니다.