스핀락과 뮤텍스의 차이점 정리
스핀락과 뮤텍스는 둘 다 임계 구역에 한 번에 하나의 스레드만 들여보내는 락이지만, 락이 풀리기를 기다리는 방법이 다릅니다. 스핀락은 루프로 락 변수를 계속 확인하는 바쁜 대기로 기다리므로 기다리는 동안에도 CPU를 계속 쓰지만, 풀리면 바로 잡을 수 있습니다. 뮤텍스는 기다리는 스레드를 슬립시켜 CPU를 내놓고, 락이 해제되면 OS가 깨워 줍니다. 보유 시간이 아주 짧은 경우나 잠들 수 없는 인터럽트 핸들러 안에서는 스핀락을, 오래 보유하는 경우나 보유 중에 잠들 가능성이 있는 경우에는 뮤텍스를 사용합니다.
| 비교 항목 | 스핀락 | 뮤텍스 |
|---|---|---|
| 대기 방식 | 락이 풀릴 때까지 루프로 변수를 계속 확인(바쁜 대기) | 풀려 있지 않으면 슬립해서 기다리고, 해제될 때 깨워 줌 |
| 대기 중의 CPU | 계속 사용 | 내놓음. 그동안 다른 스레드가 CPU를 쓸 수 있음 |
| 대기 비용 | 컨텍스트 스위치가 없고, 풀리면 바로 잡을 수 있음 | 잠들 때와 깨어날 때 시스템 콜과 컨텍스트 스위치 비용이 듦 |
| 적합한 보유 시간 | 아주 짧은 시간(컨텍스트 스위치에 걸리는 시간보다 짧음) | 긴 시간. 보유 중에 I/O를 기다리는 등 잠들 가능성이 있을 때 |
| 보유 중에 잠들기 | 해서는 안 됨. 기다리는 쪽이 CPU를 계속 쓰게 됨 | 가능 |
| 코어가 하나일 때 | 기다리는 동안 락을 가진 스레드가 실행되지 못해, 돌아도 풀리지 않음. 커널에서는 선점을 멈추고 사용 | 문제없이 사용 가능 |
| 커널 안에서의 사용 | 인터럽트 핸들러처럼 잠들 수 없는 상황(인터럽트 컨텍스트)에서도 사용 가능. 인터럽트와 데이터를 공유할 때는 인터럽트를 금지한 뒤 획득 | 잠들 가능성이 있으므로 프로세스 컨텍스트에서만 쓸 수 있고, 인터럽트 핸들러에서는 쓸 수 없음 |
| 우선순위 역전 | 락을 가진 스레드가 멈추면 기다리는 쪽이 계속 돌게 됨. 커널에서는 보유 중 선점을 금지해 방지 | 우선순위 상속이 있는 뮤텍스로 대책 가능 |
| 구현 예 | 원자적 명령(test-and-set이나 compare-and-swap)으로 변수를 바꿈. 평소에는 일반 읽기로 기다리는 test-and-test-and-set으로 코어 간 통신을 줄임 | Linux의 futex에서는 경합이 없으면 사용자 공간의 원자적 명령만으로 락을 걸고, 경합했을 때만 커널이 재워 줌. 잠시 돈 뒤에 잠드는 구현도 있음 |
수치는 대략적인 자릿수 기준이며, 공정 세대와 제품에 따라 달라져요.