스핀락 vs 뮤텍스 요약:
스핀락 뮤텍스 면접 질문의 핵심은 "지금 컨텍스트가 잠들 수 있는가, 임계구역이 얼마나 짧은가"입니다. ISR이나 인터럽트 비활성화 구간처럼 잠들 수 없고 임계구역이 아주 짧다면 스핀락을, 코드가 길어지거나 블로킹·스케줄링이 필요한 프로세스 컨텍스트라면 뮤텍스를 고른다는 기준부터 말하면 됩니다.
그 다음에 데드락 방지(락 획득 순서)와 우선순위 역전(스핀락 busy-wait이 CPU를 태우는 문제 vs 뮤텍스의 우선순위 상속) 근거를 더하면 답변이 완성됩니다.
이 글은 면접에서 스핀락과 뮤텍스를 고르는 기준을 정리한 일반 안내이며, 커널 버전·아키텍처·설정(CONFIG_PREEMPT 등)에 따라 세부 동작은 달라질 수 있습니다.
스핀락이 맞는 ISR·짧은 임계구역 신호는?
한 줄 답: 인터럽트 핸들러나 인터럽트 비활성화 구간처럼 잠들 수 없는 컨텍스트에서, 아주 짧은 코드만 보호해야 할 때는 스핀락이 맞는 신호입니다.
스핀락은 락을 못 잡으면 코드가 바쁜 대기(busy-wait)로 반복해서 재시도하는 방식입니다. 스핀락을 쥔 상태로는 잠들 수 있는 함수(메모리 할당, 세마포어 대기 등)를 호출하면 안 되므로, 스핀락 내부에서 메모리를 할당해야 한다면 GFP_ATOMIC처럼 잠들지 않는 플래그를 써야 합니다. 리눅스 커널의 spinlocks 문서는 이런 제약과 함께 spin_lock() / spin_lock_irqsave() 같은 변형이 왜 필요한지를 설명합니다.
면접에서는 다음과 같은 신호를 예로 들 수 있습니다. 인터럽트 핸들러(ISR) 안에서 공유 자료구조를 건드려야 하는 경우, 이미 다른 스핀락을 쥐고 있거나 선점이 꺼진 구간이라 잠들 수 없는 경우, 그리고 임계구역이 변수 몇 개를 읽고 쓰는 수준으로 매우 짧아서 바쁜 대기 비용이 작다고 판단되는 경우입니다.
- 컨텍스트: 지금 코드가 잠들 수 없는 컨텍스트인지(ISR, 이미 락을 쥔 상태, 선점 비활성화)부터 확인합니다.
- 임계구역 길이: 보호해야 할 코드가 몇 줄 안에 끝나는지 확인합니다.
- 대기 전제: 다른 쪽이 락을 아주 짧게만 쥐고 있어서 바쁜 대기가 길어지지 않는다는 전제가 성립하는지 확인합니다.
뮤텍스(슬립 가능)로 남겨둘 구간은?
한 줄 답: 코드가 블로킹 I/O나 메모리 할당처럼 잠들 수 있는 호출을 포함하거나 임계구역이 길어서 다른 작업을 오래 막는다면, 스핀락 대신 뮤텍스로 남겨둬야 합니다.
뮤텍스는 락을 못 잡으면 호출한 태스크를 재우고 스케줄러에 맡기는 방식이라서, 프로세스 컨텍스트처럼 잠들어도 되는 곳에서만 쓸 수 있습니다. 리눅스 커널의 mutex-design 문서는 뮤텍스가 세마포어보다 가볍고 단순한 상호배제 전용 락으로 설계된 이유와, 인터럽트 컨텍스트에서는 쓸 수 없다는 제약을 설명합니다.
면접에서는 이런 구간을 예로 들 수 있습니다. 파일·네트워크 I/O처럼 완료까지 시간이 걸리는 작업을 임계구역 안에서 호출해야 하는 경우, 임계구역 안에서 추가로 메모리를 할당해야 하는 경우, 그리고 락을 쥐는 시간이 길어서 다른 쪽을 바쁜 대기로 묶어두면 CPU 낭비가 큰 경우입니다.
- 이 코드가 ISR이 아닌 프로세스 컨텍스트에서만 실행되는지 확인합니다.
- 임계구역 안에서 잠들 수 있는 호출(블로킹 I/O, 할당, 다른 락 대기)이 있는지 확인합니다.
- 둘 중 하나라도 해당되면 스핀락을 쓰지 않고 뮤텍스로 남겨둡니다.
데드락·우선순위 역전을 면접에서 어떻게 짚나?
한 줄 답: 락 획득 순서를 고정하고 IRQ-세이프 변형을 쓰는지로 데드락을, 스핀락 busy-wait이 CPU를 태우는 상황과 뮤텍스의 우선순위 상속으로 우선순위 역전을 설명하면 됩니다.
데드락은 어떻게 짚습니까?
먼저 락 두 개 이상을 서로 다른 순서로 잡으면 데드락이 발생할 수 있다는 원칙부터 말합니다. 락 A를 먼저 잡고 락 B를 잡는 경로와, 락 B를 먼저 잡고 락 A를 잡는 경로가 동시에 존재하면 서로를 기다리며 멈출 수 있으므로, 모든 코드 경로에서 락 획득 순서를 고정하는 것이 기본 원칙입니다.
그 다음 인터럽트와 스핀락을 함께 쓸 때 생기는 중첩 문제를 짚습니다. 인터럽트 핸들러에서도 접근하는 자료구조를 보호하는 스핀락이라면, 프로세스 컨텍스트에서는 spin_lock_irqsave()처럼 인터럽트를 함께 비활성화하는 변형을 써야 합니다. 그렇지 않으면 락을 쥔 채로 인터럽트가 들어와 같은 락을 다시 요청하면서 자기 자신과 데드락에 빠질 수 있습니다.
우선순위 역전은 어떻게 짚습니까?
우선순위 역전은 낮은 우선순위 태스크가 락을 쥔 상태에서 높은 우선순위 태스크가 그 락을 기다리느라 더 낮은 우선순위처럼 동작하게 되는 상황입니다. 스핀락에서는 이 대기가 바쁜 대기이므로, 기다리는 동안 CPU 사이클을 계속 태운다는 점을 짚습니다. 반면 뮤텍스는 대기 중인 태스크를 재우므로 CPU는 낭비되지 않지만, 우선순위가 뒤바뀌는 문제 자체는 남습니다.
이를 완화하는 커널 메커니즘으로 우선순위 상속(priority inheritance)이 있다는 점을 언급할 수 있습니다. 리눅스 커널의 rt-mutex-design 문서는 낮은 우선순위 태스크가 락을 쥐고 있을 때, 그 락을 기다리는 높은 우선순위 태스크의 우선순위를 락을 쥔 태스크에 일시적으로 상속시켜 역전 구간을 줄이는 rt-mutex 구조를 설명합니다.
| 비교 항목 | 스핀락 | 뮤텍스 |
|---|---|---|
| 사용 가능 컨텍스트 | 인터럽트 컨텍스트 포함, 잠들 수 없는 곳 | 프로세스 컨텍스트, 잠들 수 있는 곳만 |
| 락을 못 잡았을 때 | 바쁜 대기(busy-wait)로 CPU 사용 | 태스크를 재우고 스케줄러에 양보 |
| 임계구역 안 호출 제약 | 잠드는 호출(블로킹 I/O, 일반 할당) 금지 | 잠드는 호출 가능 |
| 우선순위 역전 대응 | 대기 중에도 CPU를 태우므로 역전 비용이 큼 | rt-mutex 등에서 우선순위 상속으로 완화 가능 |
spin_lock_irqsave() 없이 잡는 실수는 커널 코드 리뷰에서 자주 지적되는 전형적인 버그이므로, 면접에서도 이 두 가지를 직접 언급하면 좋습니다.FAQ에서는 무엇을 확인합니까?
한 줄 답: 스핀락을 오래 쥐었을 때의 피해 범위와, 커널이 우선순위 역전을 완화하는 구체적인 방법을 확인합니다.
다른 CPU에서 같은 락을 기다리는 코드가 계속 바쁜 대기로 사이클을 소모하고, SMP가 아니더라도 그동안 인터럽트나 선점이 비활성화돼 있다면 다른 작업의 응답이 늦어집니다. 그래서 스핀락 임계구역은 가능한 한 짧게 유지해야 한다는 원칙이 함께 언급됩니다.
대표적으로 우선순위 상속을 구현한 rt-mutex가 있습니다. 낮은 우선순위 태스크가 락을 쥐고 있을 때 대기 중인 더 높은 우선순위 태스크의 우선순위를 임시로 넘겨받게 해서, 역전 구간 동안 그 태스크가 선점당하지 않도록 만드는 방식입니다. 자세한 구조는 rt-mutex-design 문서에서 확인할 수 있습니다.
정리하면 어떻게 답하면 됩니까?
스핀락과 뮤텍스를 고르는 질문은 암기 문제가 아니라, 지금 컨텍스트가 잠들 수 있는지와 임계구역이 얼마나 짧은지로 근거를 설명할 수 있는지를 보는 질문입니다. ISR이나 잠들 수 없는 짧은 구간이면 스핀락을, 길거나 블로킹 호출이 섞인 프로세스 컨텍스트 구간이면 뮤텍스를 우선 검토한다는 기준을 먼저 말하고, 필요하면 락 획득 순서로 데드락을, 우선순위 상속으로 우선순위 역전 대응을 보강하면 됩니다.
Spinlock vs. mutex summary:
The core interview question is whether your current context can sleep and how short the critical section is. If you're in an ISR or any context that cannot sleep, and the critical section is only a few lines, reach for a spinlock. If the code is longer or needs to block or get rescheduled, that's process-context work that belongs behind a mutex.
From there, reinforce the answer with deadlock avoidance (consistent lock ordering) and priority inversion (a spinning waiter burning CPU vs. a mutex's priority inheritance).
This is a general guide to answering this interview question. Exact behavior depends on kernel version, architecture, and configuration (e.g., CONFIG_PREEMPT).
What signals call for a spinlock in an ISR or short critical section?
One-line answer: A context that cannot sleep — like an interrupt handler or an interrupt-disabled region — combined with a critical section short enough to busy-wait through is the signal for a spinlock.
A spinlock makes a waiting thread busy-wait instead of sleeping. Because you can't call a sleeping function while holding one, any allocation inside the critical section has to use a non-sleeping flag such as GFP_ATOMIC. The Linux kernel spinlocks documentation explains this constraint along with variants like spin_lock() and spin_lock_irqsave().
Good interview signals: touching shared state from inside an interrupt handler, already holding another spinlock or running with preemption disabled, and a critical section that only reads or writes a handful of variables — short enough that the busy-wait cost stays small.
- Context: Confirm the code runs where it cannot sleep (ISR, already holding a lock, preemption off).
- Critical section length: Confirm the protected code finishes in just a few lines.
- Wait assumption: Confirm the other side holds the lock briefly enough that busy-waiting stays cheap.
What should stay on a sleepable mutex?
One-line answer: If the code includes a sleeping call — blocking I/O, memory allocation — or the critical section runs long enough to block other work, leave it on a mutex instead of a spinlock.
A mutex puts a waiting task to sleep and hands it back to the scheduler, so it only works in contexts where sleeping is allowed. The Linux kernel mutex-design documentation explains why the mutex was designed as a lighter, exclusion-only lock compared to a semaphore, and why it cannot be used from interrupt context.
Good examples: a critical section that calls into file or network I/O, one that needs to allocate memory internally, and any section long enough that forcing other callers to busy-wait would waste real CPU time.
- Confirm this code only ever runs in process context, never from an ISR.
- Confirm whether the critical section contains a sleeping call (blocking I/O, allocation, waiting on another lock).
- If either is true, keep it on a mutex instead of a spinlock.
How do you cover deadlock and priority inversion in the interview?
One-line answer: Explain deadlock through consistent lock-acquisition order and IRQ-safe variants, and explain priority inversion through a spinning waiter burning CPU versus a mutex's priority inheritance.
How do you explain deadlock?
Start with the core rule: acquiring two or more locks in inconsistent order across different code paths can deadlock, since each path can end up waiting on a lock the other already holds. The fix is a fixed lock-acquisition order enforced everywhere.
Then cover the IRQ-nesting case. If a spinlock is also touched from an interrupt handler, process-context code must use a variant like spin_lock_irqsave() that disables interrupts too — otherwise an interrupt firing while the lock is held can try to re-acquire the same lock and deadlock against itself.
How do you explain priority inversion?
Priority inversion happens when a low-priority task holds a lock that a higher-priority task is waiting on, effectively dragging the high-priority task down to the lower one's priority. With a spinlock, that wait is a busy-wait, so it keeps burning CPU cycles the whole time. A mutex puts the waiter to sleep instead, which stops the CPU waste, but the priority-ordering problem itself is still there.
Mention priority inheritance as the kernel mechanism that mitigates this. The Linux kernel rt-mutex-design documentation describes how an rt-mutex temporarily lends the waiting higher-priority task's priority to the lock holder, shrinking the inversion window.
| Comparison | Spinlock | Mutex |
|---|---|---|
| Valid context | Any context, including interrupt context — cannot sleep | Process context only — sleeping allowed |
| When the lock is busy | Busy-waits, spending CPU | Sleeps and yields to the scheduler |
| Calls allowed inside | No sleeping calls (blocking I/O, plain allocation) | Sleeping calls allowed |
| Priority inversion handling | Waiter still burns CPU — inversion cost is higher | Can be mitigated with priority inheritance (rt-mutex, etc.) |
spin_lock_irqsave() for a lock also touched from an interrupt handler, are classic bugs kernel code review catches often — naming both explicitly is worth doing in the interview.What does the FAQ cover?
Other CPUs waiting on the same lock keep burning cycles in a busy-wait, and if interrupts or preemption are disabled during that window, other work's response time suffers too. That's the basis for keeping spinlock critical sections as short as possible.
The main mechanism is priority inheritance, implemented in rt-mutex: a lower-priority task holding a lock temporarily borrows the priority of a higher-priority task waiting on it, so it can't be preempted away during the inversion window. See the rt-mutex-design documentation for the full structure.
How should you wrap up the answer?
This question isn't about reciting a memorized rule — it's about showing you can reason from whether the current context can sleep and how short the critical section is. Lead with the decision rule: ISR or non-sleepable short sections favor a spinlock, longer or blocking-call-containing process-context sections favor a mutex. Then reinforce it with lock-ordering for deadlock and priority inheritance for priority inversion.
'임베디드' 카테고리의 다른 글
| 인터럽트와 폴링, 임베디드 면접에서 어떻게 고르나? (0) | 2026.10.07 |
|---|---|
| 임베디드 비전용 3TOPS급 NPU SoM, Debian에서 언제 고르나? (0) | 2026.10.05 |
| Snapdragon X2 리눅스 프리뷰, Hexagon NPU는 업스트림에서 어떻게 보나? (0) | 2026.10.04 |
| udev 규칙 작성법, 장치 이름과 권한을 어떻게 고정하나 (0) | 2026.09.26 |
| aarch64 크로스 컴파일 CMake, toolchain 파일은 어떻게 쓰나 (0) | 2026.09.22 |
