스핀락 vs 뮤텍스 — 언제 바쁜 대기가 나은가
동기화에서 "잠금을 못 얻으면 어떻게 할 것인가?"에 대한 두 가지 전략이 스핀락(계속 확인)과 뮤텍스(잠들기)입니다. 상황에 따라 어느 쪽이 나은지 아는 것이 중요합니다.
스핀락 (Spinlock)
잠금을 얻을 때까지 반복 루프로 계속 확인(바쁜 대기, Busy Waiting) 합니다.
// 스핀락 의사 코드
void spin_lock(int *lock) {
while (atomic_test_and_set(lock) == 1) {
// 아무것도 안 하고 계속 확인 (CPU 사이클 소비)
}
}
void spin_unlock(int *lock) {
*lock = 0;
}
- CPU를 놓지 않고 계속 돌면서(spin) 잠금 해제를 기다림
- 잠금 해제 즉시 획득 가능 — 지연 없음
뮤텍스 (Mutex)
잠금을 못 얻으면 스레드를 슬립 상태로 전환 합니다.
// 뮤텍스 의사 코드
void mutex_lock(mutex *m) {
if (m->locked) {
// 현재 스레드를 대기 큐에 넣고 슬립
add_to_wait_queue(current_thread);
sleep();
}
m->locked = 1;
}
void mutex_unlock(mutex *m) {
m->locked = 0;
// 대기 큐에서 하나를 깨움
wakeup(wait_queue_head);
}
- 잠금을 못 얻으면 CPU를 양보하고 잠듦
- 잠금이 해제되면 OS가 깨워줌
비교
| 항목 | 스핀락 | 뮤텍스 |
|---|---|---|
| 대기 방식 | 바쁜 대기 (CPU 사용) | 슬립 (CPU 양보) |
| 컨텍스트 스위칭 | 없음 | 있음 (sleep/wakeup) |
| CPU 낭비 | 대기 중 CPU 100% 사용 | 없음 |
| 잠금 해제 시 반응 | 즉시 | 깨어나는 데 시간 소요 |
| 적합한 상황 | 짧은 임계 구역 | 긴 임계 구역 |
| 멀티코어 | 효과적 | 상관없음 |
| 싱글코어 | 의미 없음 | 적합 |
언제 스핀락이 나은가
잠금 보유 시간 < 컨텍스트 스위칭 비용
→ 스핀락이 유리
잠금 보유 시간 > 컨텍스트 스위칭 비용
→ 뮤텍스가 유리
스핀락이 적합한 상황:
- 임계 구역이 매우 짧을 때 (수십~수백 나노초)
- 멀티코어 환경 — 다른 코어에서 잠금이 해제될 수 있음
- 커널 내부 — 인터럽트 핸들러 등 슬립할 수 없는 컨텍스트
뮤텍스가 적합한 상황:
- 임계 구역이 길 때 (I/O 작업 포함 등)
- 싱글코어 — 스핀락은 CPU를 독점하므로 다른 스레드가 잠금을 해제할 수 없음
- 유저 공간 프로그래밍
리눅스 커널에서의 스핀락
// 리눅스 커널 스핀락 사용
spinlock_t my_lock;
spin_lock_init(&my_lock);
spin_lock(&my_lock);
// 짧은 임계 구역 (인터럽트 비활성화 가능)
spin_unlock(&my_lock);
// 인터럽트를 비활성화하면서 잠금 (인터럽트 핸들러에서 같은 잠금 사용 시)
spin_lock_irqsave(&my_lock, flags);
// 임계 구역
spin_unlock_irqrestore(&my_lock, flags);
커널에서 스핀락을 쓰는 이유:
- 인터럽트 핸들러에서는 슬립할 수 없음 (뮤텍스 사용 불가)
- 스케줄러 자체를 보호할 때 — 스케줄러가 잠들 수는 없으니
하이브리드: Adaptive Mutex
실제 구현에서는 순수 스핀락이나 순수 뮤텍스보다 하이브리드 방식이 많습니다.
잠금 시도:
1. 먼저 일정 횟수만큼 스핀 (짧은 대기 최적화)
2. 그래도 못 얻으면 슬립으로 전환 (긴 대기 최적화)
- Linux의 futex (Fast Userspace Mutex): 경쟁이 없으면 시스템 콜 없이 유저 공간에서 처리, 경쟁 시에만 커널 개입
- Java의 synchronized: 먼저 스핀을 시도하고, 실패하면 OS 뮤텍스로 전환
핵심 포인트
- 스핀락을 싱글코어에서 쓰면 안 되는 이유: 스핀하는 동안 잠금을 가진 스레드가 실행될 수 없음 → CPU만 낭비
- 커널이 스핀락을 쓰는 이유: 인터럽트 컨텍스트에서 슬립 불가능
- Java synchronized의 내부: 편향 잠금 → 경량 잠금(스핀) → 무거운 잠금(OS 뮤텍스) 단계적 전환
정리
| 판단 기준 | 스핀락 | 뮤텍스 |
|---|---|---|
| 임계 구역 길이 | 매우 짧음 | 길거나 불확실 |
| CPU 코어 수 | 멀티코어 | 상관없음 |
| 컨텍스트 | 커널/인터럽트 | 유저 공간 |
| I/O 포함 여부 | 없음 | 있을 수 있음 |
실제로는 대부분의 경우 뮤텍스(또는 하이브리드)를 쓰고, 스핀락은 커널 개발이나 극도로 짧은 임계 구역에서만 사용합니다.