동기화에서 "잠금을 못 얻으면 어떻게 할 것인가?"에 대한 두 가지 전략이 스핀락(계속 확인)과 뮤텍스(잠들기)입니다. 상황에 따라 어느 쪽이 나은지 아는 것이 중요합니다.


스핀락 (Spinlock)

잠금을 얻을 때까지 반복 루프로 계속 확인(바쁜 대기, Busy Waiting) 합니다.

스핀락과 뮤텍스 동작 비교

C
// 스핀락 의사 코드
void spin_lock(int *lock) {
    while (atomic_test_and_set(lock) == 1) {
        // 아무것도 안 하고 계속 확인 (CPU 사이클 소비)
    }
}

void spin_unlock(int *lock) {
    *lock = 0;
}
  • CPU를 놓지 않고 계속 돌면서(spin) 잠금 해제를 기다림
  • 잠금 해제 즉시 획득 가능 — 지연 없음

뮤텍스 (Mutex)

잠금을 못 얻으면 스레드를 슬립 상태로 전환 합니다.

C
// 뮤텍스 의사 코드
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% 사용없음
잠금 해제 시 반응즉시깨어나는 데 시간 소요
적합한 상황짧은 임계 구역긴 임계 구역
멀티코어효과적상관없음
싱글코어의미 없음적합

언제 스핀락이 나은가

PLAINTEXT
잠금 보유 시간 < 컨텍스트 스위칭 비용
→ 스핀락이 유리

잠금 보유 시간 > 컨텍스트 스위칭 비용
→ 뮤텍스가 유리

스핀락이 적합한 상황:

  • 임계 구역이 매우 짧을 때 (수십~수백 나노초)
  • 멀티코어 환경 — 다른 코어에서 잠금이 해제될 수 있음
  • 커널 내부 — 인터럽트 핸들러 등 슬립할 수 없는 컨텍스트

뮤텍스가 적합한 상황:

  • 임계 구역이 길 때 (I/O 작업 포함 등)
  • 싱글코어 — 스핀락은 CPU를 독점하므로 다른 스레드가 잠금을 해제할 수 없음
  • 유저 공간 프로그래밍

리눅스 커널에서의 스핀락

C
// 리눅스 커널 스핀락 사용
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

실제 구현에서는 순수 스핀락이나 순수 뮤텍스보다 하이브리드 방식이 많습니다.

PLAINTEXT
잠금 시도:
1. 먼저 일정 횟수만큼 스핀 (짧은 대기 최적화)
2. 그래도 못 얻으면 슬립으로 전환 (긴 대기 최적화)
  • Linux의 futex (Fast Userspace Mutex): 경쟁이 없으면 시스템 콜 없이 유저 공간에서 처리, 경쟁 시에만 커널 개입
  • Java의 synchronized: 먼저 스핀을 시도하고, 실패하면 OS 뮤텍스로 전환

핵심 포인트

  • 스핀락을 싱글코어에서 쓰면 안 되는 이유: 스핀하는 동안 잠금을 가진 스레드가 실행될 수 없음 → CPU만 낭비
  • 커널이 스핀락을 쓰는 이유: 인터럽트 컨텍스트에서 슬립 불가능
  • Java synchronized의 내부: 편향 잠금 → 경량 잠금(스핀) → 무거운 잠금(OS 뮤텍스) 단계적 전환

정리

판단 기준스핀락뮤텍스
임계 구역 길이매우 짧음길거나 불확실
CPU 코어 수멀티코어상관없음
컨텍스트커널/인터럽트유저 공간
I/O 포함 여부없음있을 수 있음

실제로는 대부분의 경우 뮤텍스(또는 하이브리드)를 쓰고, 스핀락은 커널 개발이나 극도로 짧은 임계 구역에서만 사용합니다.

댓글 로딩 중...