Q.뮤텍스와 세마포어의 차이를 설명해주세요.
소유권이 있는지가 핵심입니다.
| 항목 | 뮤텍스 | 세마포어 |
|---|
| 목적 | 상호 배제 | 자원 개수 관리와 신호 전달 |
| 값 | 잠김과 풀림 | 0 이상의 정수 |
| 소유권 | 있다. 잠근 스레드만 푼다 | 없다. 누구나 올릴 수 있다 |
| 동시 통과 | 하나 | 초기값만큼 |
소유권이 실무에서 중요한 이유는 실수를 잡아주기 때문입니다. 다른 스레드가 남의 잠금을 푸는 코드는 뮤텍스에서 오류로 드러나지만 세마포어에서는 조용히 통과해 두 스레드가 동시에 임계 구역에 들어갑니다.
세마포어는 상호 배제 말고도 쓸 수 있습니다. 한쪽이 신호를 올리고 다른 쪽이 기다리는 생산자 소비자 구조가 그것입니다. 뮤텍스로는 그 표현이 안 됩니다.
흔한 실수: 세마포어를 "여러 개 통과시키는 뮤텍스"로만 답하는 것. 소유권 유무와 신호 전달 용도가 더 본질적인 차이입니다.
Q.이진 세마포어와 뮤텍스의 차이는?
값의 범위는 같지만 소유권과 용도가 다릅니다.
| 항목 | 이진 세마포어 | 뮤텍스 |
|---|
| 값 | 0 또는 1 | 잠김과 풀림 |
| 잠근 주체만 해제 | 아니다 | 그렇다 |
| 초기값 | 0 으로 시작할 수 있다 | 항상 풀린 상태로 시작 |
| 재진입 | 없다 | 구현에 따라 지원한다 |
| 우선순위 역전 대응 | 없다 | 상속 기법을 지원하는 구현이 있다 |
초기값 0 이 가능하다는 점이 용도 차이를 만듭니다. 세마포어는 아직 아무도 안 가진 상태로 시작해, A 가 신호를 올릴 때까지 B 가 기다리는 순서 제어에 쓸 수 있습니다. 뮤텍스는 이 표현이 안 됩니다.
흔한 실수: 둘이 사실상 같다고 답하는 것. 상호 배제에는 뮤텍스를 쓰는 것이 원칙이고, 이유는 남이 푸는 실수를 막고 우선순위 역전 대응이 가능하기 때문입니다.
Q.경쟁 조건(Race Condition)이란 무엇인가요?
여러 실행 흐름이 공유 자원에 동시에 접근할 때, 실행 순서에 따라 결과가 달라지는 상태입니다.
스레드 A 는 잔액에 100을 더하고, B 는 50을 뺀다
| 순서 | 동작 | 잔액 |
|---|
| 1 | A 가 읽는다 | 1000 |
| 2 | B 가 읽는다 | 1000. 아직 A 가 쓰지 않았다 |
| 3 | A 가 쓴다 | 1100 |
| 4 | B 가 쓴다 | 950. A 의 변경이 사라졌다 |
원인은 읽고 계산해서 쓰는 것이 원자적이지 않기 때문입니다. 중간에 끼어들 틈이 있습니다.
| 해결 | 방법 |
|---|
| 잠금 | 임계 구역을 뮤텍스로 감싼다 |
| 원자적 연산 | 하드웨어가 보장하는 증감 연산을 쓴다 |
| 공유하지 않는다 | 스레드마다 따로 계산하고 마지막에 합친다 |
| 조건부 갱신 | DB 라면 조건과 갱신을 한 문장으로 |
흔한 실수: 재현이 어려워 없다고 판단하는 것. 타이밍에 따라 드물게 나타나므로 테스트에서 안 보여도 운영에서 터집니다.
Q.실무에서 세마포어가 사용되는 예시를 들어주세요.
동시에 N개까지만 허용해야 하는 자리입니다.
| 예 | 초기값 |
|---|
| DB 커넥션 풀 | 최대 연결 수 |
| 외부 API 호출 제한 | 초당 허용 호출 수 |
| 파일 다운로드 동시 실행 수 | 대역폭을 고려한 값 |
| 무거운 작업의 동시 실행 제한 | 코어 수 안팎 |
| 생산자 소비자 큐 | 빈 자리 수와 채워진 수 각각 |
마지막은 상호 배제가 아니라 신호 전달입니다. 큐가 비었으면 소비자가 기다리고, 생산자가 넣으면 신호를 올려 깨웁니다.
주의할 것은 반납입니다. 예외가 난 경로에서 반납을 빼먹으면 카운트가 한 방향으로만 줄어 결국 모두 멈춥니다. 획득과 반납을 자원 관리 구문으로 묶어야 합니다.
흔한 실수: 세마포어로 상호 배제를 구현하는 것. 동작은 하지만 소유권이 없어 남이 푸는 실수를 못 막습니다. 하나만 통과시켜야 하면 뮤텍스입니다.
먼저 스스로 답해보고 아래 답변과 견줘보세요. 막히는 부분은 문제로 확인할 수 있어요.
읽었으면 문제로 확인해보세요
운영체제 문제를 풀면 틀린 문제가 자동으로 노트에 쌓입니다. 가입 없이 5문제를 먼저 풀어볼 수도 있어요.