락 (Lock) / 뮤텍스 (Mutex) — 스레드 간 상호 약속으로 임계 영역을 보호하는 메커니즘. 락을 쥔 스레드만 임계 영역에 진입하고, 잠근 스레드가 풀어준다. 공유 변수로 락 상태(잠김/풀림)와 소유자를 표현한다. 문제 제기와 다른 보호 방식은 공유 자원과 경쟁 상태 참고.

락 변수 구성

  • 공유 변수
  • Lock state — 잠김 / 풀림
  • Lock owner — 누가 쥐고 있는가 (소유권은 필수는 아니지만 제대로 된 뮤텍스라면 잠근 스레드만 풀 수 있다)

순진한 구현과 그 취약점

플래그만 사용한 구현.

typedef struct _lock_t { int flag; } lock_t;
 
void init(lock_t *mutex) {
    mutex->flag = 0;   // 0 = available, 1 = held
}
 
void lock(lock_t *mutex) {
    while (mutex->flag == 1)   // TEST
        ;                       // spin-wait
    mutex->flag = 1;            // SET
}
 
void unlock(lock_t *mutex) {
    mutex->flag = 0;
}

문제: while 루프 탈출 직후·flag = 1 이전에 선점되면 두 스레드가 동시에 락을 얻는다. TEST와 SET이 원자적이지 않기 때문. 이 틈새를 막으려면 하드웨어 지원이 필요하다.

하드웨어 지원 원자 명령

Test-and-Set

“값 읽기 + 새 값 쓰기”를 한 명령에 원자적으로 수행.

int TestAndSet(int *old_ptr, int new) {   // Atomic
    int old = *old_ptr;
    *old_ptr = new;
    return old;
}

Compare-and-Swap (CAS)

기대값과 일치할 때만 교체.

int compare_and_swap(int *reg, int oldval, int newval) {   // Atomic
    int old_reg_val = *reg;
    if (old_reg_val == oldval)
        *reg = newval;
    return old_reg_val;
}

안전한 구현 (Test-and-Set 기반)

void lock(lock_t *mutex) {
    while (TestAndSet(&mutex->flag, 1) == 1)
        ;   // spin-wait
}
 
void unlock(lock_t *mutex) {
    mutex->flag = 0;
}

TestAndSet이 원자적으로 “이전 값을 돌려주면서 1로 세팅”하므로 경쟁 창이 사라진다.

락 획득 실패 시 거동 — Spinlock vs Mutex

구분SpinlockMutex (Blocking Lock)
대기 방식락 변수를 계속 확인하며 루프스레드를 대기 큐로 이동하고 블록
CPU 사용낭비낭비 없음
진입 지연추가 지연 없음waiting→ready 이동 + 새 스레드 선택 시간
적용 범위멀티코어 간 공유 자원 (다른 코어가 풀어줌)코어 내부(intra-core) 공유 자원
해제 동작플래그만 0으로unlock()이 블록된 스레드를 깨움

짧은 임계 영역 + 멀티코어 조합에는 spinlock이, 긴 임계 영역 + 단일 코어 상황에는 mutex가 맞다. 단일 코어에서 spinlock은 락을 쥔 스레드가 실행될 기회를 자신이 막기 때문에 의미가 없다.

락 입도 (Lock Granularity)

공유 자원이 많을 때 락을 어떻게 묶을 것인가 의 설계 선택.

방식특성
Fine-granular자원마다 개별 락 — 병렬성↑, 락 변수 많음, 코드 복잡도↑
Coarse-granular여러 자원을 묶어 하나의 락으로 — 단순, 불필요한 블록 발생

결정적 트레이드오프: 병렬성 vs 단순성.

락이 유발하는 문제

락은 다시 두 가지 고질병을 낳는다.

  • 데드락 — 둘 이상 태스크가 서로의 락을 기다리며 진행 불가
  • 우선순위 역전 — 낮은 우선순위 태스크가 높은 우선순위 태스크를 블로킹

두 문제를 완화·해결하는 프로토콜 모음은 리소스 공유 프로토콜 참고.

같이 보기