CS
[OS] 뮤텍스와 세마포어
chocoji
2024. 5. 12. 11:01
임계 구역(Critical Section)
공유 자원의 일관성을 보장하기 위해 하나의 프로세스/스레드만 진입해서 실행 가능한 영역
- `공유 자원`: 여러 프로세스 혹은 스레드가 공유하는 자원
- ex. 전역 변수, 파일, I/O 장치, 보조기억장치 등
- 임계 구역에 진입하고자 하면, 진입한 프로세스 이외의 다른 프로세스는 대기해야 한다.
- 임계 구역에 동시에 접근하면 자원의 일관성이 깨질 수 있다.
임계 구역 문제
임계 구역으로 지정되어야 할 코드 영역이 임계 구역으로 지정되지 않았을 때 발생하는 문제
경쟁 상태(Race Condition)
- 여러 프로세스가 공유 자원에 동시에 접근할 때, 접근의 타이밍이나 순서 등이 결괏값에 영향을 줄 수 있는 `경쟁 상태(race condition)`가 발생할 수 있다.
임계 구역 문제 해결 조건
임계 구역 문제를 해결하려면 다음 세 가지 조건을 모두 만족해야 한다.
상호 배제(Mutual Exclusion)
- 한 프로세스가 자신의 임계 구역에 있다면 다른 프로세스들은 임계 영역에 진입할 수 없다.
진행(Progress)
- 아무도 임계 구역에 있지 않다면, 진입하고자 하는 프로세스를 진입하게 해줘야 한다.
유한 대기(Bounded Waiting)
- 프로세스가 임계 영역에 진입하기 위해 무한정으로 기다리는 `기아 상태(Starvation)`가 발생해서는 안 된다.
- `기아 상태`: 우선순위에 의하여 특정 프로세스가 원하는 자원을 영원히 할당받지 못하는 상태
동기화 도구 - 뮤텍스, 세마포어
- `상호배제`를 달성하기 위한 기법
- `동기화(Synchronization)`: 공유 자원에 동시에 접근하지 못하도록 프로세스의 실행 순서를 제어하여 데이터의 일관성을 유지하는 방법
- 공유 자원의 데이터를 여러 프로세스/스레드가 접근하는 것을 막는다.
뮤텍스(Mutex)
`상호배제(Mutual Exclusion)`의 약자로, 말 그대로 상호 배제를 위한 기법
단일 스레드/프로세스만이 공유 자원에 접근할 수 있다.
- 단일 스레드/프로세스에 소유될 수 있는 key를 기반으로 하는 방식으로, key에 해당하는 객체를 고유한 스레드/프로세스만이 공유 자원에 접근할 수 있다.
- 공유 자원을 사용하기 전에 lock을 걸고, 사용한 후 잠금을 해제(unlock)한다.
- 이때 다른 프로세스/스레드는 접근할 수 없다.
mutex = 1;
void lock () {
while (mutex != 1)
{
// mutex 값이 1이 될 때까지 대기
}
// 이 구역에 도착했다는 것은 mutex 값이 1이라는 뜻. 이제 뮤텍스 값을 0으로 만들어 다른 프로세스(혹은 쓰레드)의 접근을 제한
mutex = 0;
}
void unlock() {
// 임계 구역에서 수행을 완료한 프로세스는 다른 프로세스가 접근할 개수 있도록 뮤텍스 값을 1으로 만들어 락을 해제.
mutex = 1;
}
- `mutex == 1`: 임계 구역에 진입할 수 있는 상태
- `mutex == 0`: 임계 구역에 진입할 수 없는 상태
특징
- 단순하고 직관적
- 주어진 시간에 하나의 스레드만 임계 구역에 있기 때문에 경쟁 상태가 발생하지 않는다.
- 락을 얻지 못하고 무한히 대기할 수 있는 프로세스가 발생할 수 있다.
세마포어(Semaphore)
하나 이상의 프로세스/스레드가 임계 영역에 접근할 수 있도록 하는 장치
- 공유자원에 접근할 수 있는 자원의 최댓값을 나타내는 `정수값`을 이용해 상호배제를 달성한다.
- 최대 허용치만큼 동시에 사용자가 접근할 수 있으며, 각 프로세스는 세마포어의 값을 확인하고 변경할 수 있다.
- 여러 프로세스/스레드가 동시에 접근할 수 있으므로, 동기화 대상이 둘 이상일 때 사용한다.
세마포어 접근 함수 - `wait()`, `signal()`
- `wait()`
- 사용 가능한 공유 자원이 있으면 세마포어 변수를 -1 처리한 후 사용한다.
- 사용 가능한 공유 자원이 없으면 기다린다.
- `signal()`
- 공유 자원을 모두 사용한 후 세마포어 변수를 +1 처리한다.
- 공유 자원 사용을 완료했다는 신호를 보낸다.
// Shared Data
semaphore mutex; // 세마포어 변수 mutex의 초기값은 자원의 갯수를 의미.
// Process P
do {
wait(mutex);
/* critical section */
signal(mutex);
/* remainder section */
} while (1);
// fun wait()
fun wait(S) {
while(S <= 0);
S--;
}
// fun signal()
fun signal(S) {
S++;
}
세마포어를 활용한 실행 순서 동기화 방법
- 세마포 변수 S를 0으로 초기화
- 먼저 실행할 프로세스 뒤에 signal 함수 호출
- 다음에 실행할 프로세스 앞에 wait 함수 호출
이렇게 설정하면 P2가 먼저 실행되더라도 P2는 `wait()` 함수를 만나므로 P1이 먼저 임계 구역에 진입하게 된다.
세마포어 종류
- 이진(Binary) 세마포어: 이진값(0 또는 1)만 가질 수 있다. (초깃값은 1)
- 카운팅(Counting) 세마포어: 음수 이외의 값으로 초기화될 수 있다.
뮤텍스와 이진 세마포어는 같은 것일까❓
둘 다 임계 구역에 하나의 스레드만 접근하도록 보장하기 때문에, 둘이 같다고 보는 의견도 많다.
하지만 뮤텍스는 락을 가진 자만이 락을 해제할 수 있지만, 세마포어는 락을 설정한 프로세스와 해제하는 프로세스가 다를 수 있다는 차이점이 있기 때문에 다른 것으로 봐야한다고 생각한다.
이러한 특징 때문에 뮤텍스는 자원의 일관성을 유지할 수 있으며, 단일 리소스 보호에 특화되어 있기 때문에 단일 임계 구역을 관리하기 위한 목적이라면 이진 세마포어보다 뮤텍스가 더 적합해 보인다.
🔗 https://stackoverflow.com/questions/62814/difference-between-binary-semaphore-and-mutex
특징
- 여러 프로세스/스레드가 임계 영역에 접근할 수 있다.
- 다중 리소스를 관리하기 때문에 뮤텍스에 비해 더 많은 오버헤드가 발생한다.
뮤텍스 vs 세마포어
차이점 비교
- 뮤텍스는 동기화 대상이 1개일 때, 세마포어는 1개 이상일 때 사용한다.
- 뮤텍스는 객체이고, 세마포어는 정수 변수이다.
- 뮤텍스는 락을 소유하고 있는 프로세스/스레드만이 락을 해제할 수 있지만, 세마포어는 락을 걸지 않은 프로세스/스레드도 락을 해제할 수 있다.
적합한 상황
- 1개의 자원에 대한 상호 배제만 필요하다면 뮤텍스
- 공유 자원 접근 수를 조절하고, 작업 간의 실행 순서 동기화가 필요하다면 세마포어
Ref
https://hudi.blog/race-condition-critical-section-mutual-exclusion/
https://www.joinc.co.kr/w/Site/Thread/Beginning/Mutex
https://codegym.cc/ko/groups/posts/ko.220.myutegseu-moniteo-mich-semapo-eoui-chaijeom
https://www.youtube.com/watch?v=NL9JQh5bbZ8
https://www.guru99.com/ko/mutex-vs-semaphore.html#key-difference-between-mutex-and-semaphore
https://mierminusone.tistory.com/4