수업
🧵 주제
멀티스레드 환경에서 Lock을 직접 구현할 때 선택할 수 있는 세 가지 전략(Spin, Sleep, Event)의 개념, 장단점, 성능, 문맥 교환 비용의 이해
이 글은 mutex 같은 고수준 동기화 도구 대신, 직접 Lock을 구현해야 하는 상황에서 어떤 방식으로 락을 구현할 수 있는지, 그리고 각 방식이 가지는 성능적 특징과 비용을 상세히 설명한다. 특히 운영체제의 스케줄링, context switching, 캐시/레지스터 구조까지 엮어 락 구현이 하드웨어적으로 어떤 영향을 미치는지에 대해서도 통합적으로 다룬다.
📘 개념
✅ Lock 충돌 시 대응 방식: 세 가지 전략
멀티스레드 환경에서 락이 이미 걸려 있을 때, 다른 스레드가 락을 획득하고자 시도할 수 있는 전략은 크게 세 가지로 나뉜다.
1. 무작정 기다린다 – Spin Lock (좀비 메타)
- 락이 풀릴 때까지 계속 반복 시도하며 대기
while (locked) continue; 구조로 흔히 표현됨
- 대표적 구현체:
SpinLock, std::atomic_flag
📌 장점:
- 락이 짧은 시간 동안만 걸려 있다면 즉시 접근 가능
- 컨텍스트 스위칭이 없으므로 오버헤드가 낮음
📉 단점:
- CPU 자원을 계속 점유하므로 비효율적
- 다른 스레드나 코어의 작업을 방해할 수 있음
🖼️ 그림 해석:
- 초록색 웃는 이모지가 자물쇠 앞에 계속 대기 → “기다리자!”
- 아무 일도 하지 않고 버티는 모습 = 좀비처럼 CPU를 계속 소비하는 상태
2. 잠시 물러났다가 다시 시도 – Sleep 방식 (랜덤 메타)
- 락이 걸려 있으면
sleep()이나 yield() 등을 호출해 일정 시간 자리를 비움
- 이후 다시 돌아와 락을 시도
📌 장점:
- Spin보다 CPU 낭비가 덜함
- 다른 스레드에게 CPU 기회를 줄 수 있음
📉 단점:
- 반응성이 떨어짐 (락이 바로 풀렸는데도 기회를 놓칠 수 있음)
sleep/wakeup 간격을 잘못 설정하면 효율이 급격히 낮아짐
- 컨텍스트 스위칭 비용 발생
🖼️ 그림 해석:
- “I will be back”이라고 말하며 떠나는 초록 이모지 → 일정 시간 뒤 다시 돌아옴
- 타이밍이 맞을 수도, 안 맞을 수도 있는 랜덤 요소를 비유한 구조
3. 외부에 알림 요청 – Event 방식 (갑질 메타)
- 락이 잡혀 있으면, Condition Variable, Future, Event 등으로 다른 작업을 하면서 대기
- 락이 풀리면 이벤트로 알림을 받고 다시 락 시도
📌 장점:
- 가장 효율적인 자원 사용
- 실제 시스템/서비스에서 가장 많이 사용하는 방식
📉 단점:
- 컨텍스트 스위칭 발생
- 구현 복잡도 높음 (OS 시그널링, 큐 관리 등)
🖼️ 그림 해석:
- “직원에게 부탁” → 내가 직접 락을 시도하지 않고, 직원(Event 시스템)이 알려주기를 기다림
- 갑질처럼 보이지만, 실제로는 효율적이고 표준적인 방식
✅ 이동 비용 (Context Switching)
락 대기 전략 중 Sleep이나 Event 방식은 문맥 전환(Context Switching)을 동반하게 되며, 이때 성능 저하가 발생한다.
📌 Context Switching 과정:
1. 현재 스레드의 상태(레지스터, 스택 포인터 등)를 RAM에 저장
2. 다음 스레드의 상태를 RAM에서 불러와 레지스터에 복원
3. 캐시/레지스터 미스가 발생할 수 있어 성능 저하
🧠 관련 개념:
- PCB(Process Control Block): 각 스레드의 상태를 저장하는 구조체
- 레지스터/캐시 히트 미스 = 핵심 오버헤드 발생 포인트
🖼️ 그림 해석:
- “ROOKISS의 고급 식당” 그림에서 레지스터 → L1 캐시 → L2 캐시 → RAM 순으로 데이터 이동
- 식당에서 관리자(스레드)가 바뀌며 주방과 계산대를 오가는 장면으로 표현
- 영혼이 빠져나가는 관리자 = Context Switching 발생으로 인한 상태 유실
📚 용어 정리
| 용어 | 설명 |
|---|
| SpinLock | 락이 풀릴 때까지 계속 루프를 돌며 기다리는 방식 |
| Sleep | 일정 시간 후 다시 락을 시도하기 위해 자리를 비우는 방식 |
| Event / Condition Variable | 외부에서 알림을 받아 락 시도를 재개하는 방식 |
| Context Switching | 스레드 간 전환 시 상태 저장/복원을 포함한 동작 |
| PCB | 프로세스 상태 정보가 저장되는 자료 구조 |
| Register | CPU 내부의 가장 빠른 저장 공간 |
| Cache | L1, L2 등으로 구성된 중간속도의 임시 저장 공간 |
| RAM | 일반 메모리. 컨텍스트 정보는 RAM으로 백업됨 |
🎯 핵심
- Lock을 직접 구현할 때는 상황에 맞춰 세 가지 전략 중 선택해야 한다:
- Spin – 이동 비용 없음, CPU 사용 많음, 반응 빠름
- Sleep – 이동 비용 있음, CPU 절약, 반응은 느림
- Event – 이동 비용 큼, 구현 복잡, 자원 효율 최고
- 컨텍스트 스위칭은 매우 비싼 연산이며, 레지스터와 RAM 사이의 데이터 백업/복원 과정이 동반된다.
- 시스템 구조, 락 대기 시간, 스레드 밀도에 따라 적절한 전략 선택이 중요하며, 경우에 따라 혼합 방식도 가능하다.
- 이 모든 이해는 추후 Lock-Free 구조, Atomic 연산, std::condition_variable, SpinLock 최적화 등에 대한 기반이 된다.