세마포어, 뮤텍스, 스핀 락에 대해 알기 전에 이것들이 언제 쓰이고 왜 쓰이는 지 먼저 알아야 한다.
멀티 코어 시스템에서는 여러 프로세스가 동시에 실행되어 시스템의 성능 향상을 목표로 한다. 이러한 환경에서 하나의 공유 자원을 한 프로세스가 사용중일 때, 다른 프로세스가 동시에 사용하려고 하면 여러 문제가 발생한다. 서로 같은 값을 변경하려고 하거나 읽는 도중에 값이 바뀌어 오류가 생길 수도 있다. 이러한 문제들을 동기화 문제라고 하며 이렇게 동시에 사용될 수 있는 자원을 임계 영역이라고 한다.
임계 영역에 대해 알아본 후에 세마포어, 뮤텍스, 스핀락에 대해 알아보자.
임계 영역이란 프로세스 간의 공유 자원을 접근하는 데 있어서 문제가 발생하지 않도록 한 번에 하나의 프로세스만 이용하도록 다른 프로세스의 접근을 제한하는 영역을 말한다.
임계영역이 락이 걸려서 진입이 불가능할 때, 임계영역이 언락되어 진입이 가능해질 때까지 루프를 돌면서 재시도하여 스레드가 CPU를 점유하고 있는 상태이다.
CPU를 점유하여 무의미한 코드를 계속 수행하면서 임계영역이 언락되길 기다리는 것이기 때문에 스핀락은 Busy Waiting 상태이다.
스핀락은 운영체제의 스케줄링 지원을 받지 않기 때문에, 해당 스레드에 대한 문맥 교환(context switch)이 일어나지 않는다.
임계영역이 짧은 시간 안에 언락되어 진입이 가능한 상태이면 context switch 비용이 들지 않아 효율적일 수 있지만, 임계영역이 오랜 시간동안 언락되지 않으면 그 시간동안 계속 CPU를 점유하고 있어 다른 스레드가 사용하지 못하기 때문에 오버헤드도 존재한다.
스핀락은 상태가 오직 획득(Lock)
/ 해제(Unlock)
만 존재하기에 한 번에 하나의 컴포넌트만 접근이 가능하며, 획득과 해제의 주체는 동일해야 한다.
스핀락은 context switch가 일어나지 않기 때문에 멀티 프로세서 시스템에서만 사용 가능하다.
Mutex는 Mutual Exclusion의 약자로서 상호 배제라고도 한다. 뮤텍스는 상태가 오직 획득(Lock)
/ 해제(Unlock)
만 존재한다는 점은 스핀락과 동일하다. 하지만 스핀락이 임계영역이 언락되어 권한을 획득하기까지 Busy Waiting
상태를 유지한다면, 뮤텍스는 Sleep 상태로 들어갔다 Wakeup 되면 다시 권한 획득을 시도한다.
뮤텍스의 경우에는 Locking 메커니즘으로 락을 걸은 스레드만이 임계영역을 나갈 때 락을 해제할 수 있습니다.
시스템 전반의 성능에 영향을 주고 싶지 않고 길게 처리해야하는 작업인 경우에 주로 사용된다. 주로 스레드 작업에서 많이 사용된다.
스핀락과 뮤택스와 달리 표현형이 정수형이다. 이 점을 살려 하나 이상의 컴포넌트가 공유자원에 접근할 수 있도록 허용할 수 있다.
컴포넌트가 특정 자원에 접근할 때 semWait이 먼저 호출되어 임계영역에 들어갈 수 있는지 먼저 확인한다. 임계영역에 접근이 가능하다면 semWait을 빠져나와 임계영역에 들어가고, 이후 semSignal이 호출되어 임계영역에서 빠져나옵니다.
세마포어는 Signaling 메커니즘으로 락을 걸지 않은 스레드도 signal을 통해 락을 해제할 수 있다.
위 그림과 같이 TASK A
가 먼저 스케줄링되어 post_work()를 먼저 할 수 있는 상황이고 초기 세마포어의 값을 0으로 초기화 하여 post_work를 호출하지 못한다고 하자. 그러고 TASK B
의 pre_work()가 끝난 후 세마포어의 값을 올려 TASK A
의 post_work()를 호출할 수 있도록 할 수 있다.
세마포어의 값은 자원의 수를 의미하고, 세마포어는 사용할 수 있는 자원의 개수에 따라 두가지 유형이 있다.
참고
한재엽님 Github - 운영체제
https://yoongrammer.tistory.com/63
https://cocoon1787.tistory.com/541
https://ko.wikipedia.org/wiki/스핀락
https://selfish-developer.com/entry/스핀락-뮤텍스-세마포어