스레드

배경 — 왜 스레드가 필요한가?

두 가지 이상의 일을 동시에 처리하려면 추가 프로세스를 생성해야 한다.
그런데 이 방식에는 두 가지 문제가 있다.

  • 컨텍스트 스위칭 비용 — 프로세스 전환 시 저장·복원해야 할 정보가 많다.
  • 데이터 공유의 번잡함 — 프로세스 간 통신(IPC)이 별도로 필요하다.

해결 방향: 저장·복원하는 정보를 줄여 컨텍스트 스위칭 비용을 낮추자.


스레드란?

하나의 프로세스 내에서 여러 실행 흐름을 두기 위한 모델.

메모리 구조

영역스레드 간 공유 여부
코드(Code)공유
데이터(Data)공유
힙(Heap)공유
스택(Stack)각 스레드가 독립 보유

스택만 독립적으로 가진다 — 실행 흐름을 추가하기 위한 최소 조건이기 때문.


왜 컨텍스트 스위칭이 가벼운가?

흔히 “복원해야 할 레지스터가 적어서”라고 생각하기 쉽지만, 더 본질적인 이유는 캐시 히트 확률에 있다.

같은 프로세스 내의 스레드들은 코드·데이터·힙을 공유한다.
따라서 스레드 간 전환이 일어나도 캐시에 올라와 있는 데이터가 그대로 유효할 가능성이 높다.

반면 프로세스 간 전환은 주소 공간 자체가 바뀌므로 캐시가 무효화되어 캐시 미스가 대거 발생한다.

결국 스레드 컨텍스트 스위칭이 가벼운 핵심 이유는 레지스터 수가 아니라, 캐시를 재활용할 수 있기 때문이다.


유저 영역과 커널 영역

메모리는 활용 대상에 따라 두 영역으로 나뉜다.

영역설명
유저 영역사용자가 구현한 프로그램 동작 시 사용하는 메모리 (코드/데이터/힙/스택)
커널 영역운영체제 동작 시 사용하는 메모리

유저 모드와 커널 모드

프로세서(CPU)는 두 가지 모드 중 하나로 동작한다.

  • 유저 모드 — 커널 영역으로의 접근이 금지된다. 일반적인 프로그램 실행 시의 기본 모드.
  • 커널 모드 — 모든 메모리 영역에 접근이 허용된다. 커널이 실행되어야 할 때 전환된다.

모드 간 전환(유저 → 커널 → 유저)은 시스템에 부담을 주는 작업이다.
타임슬라이스에 따른 스케줄러 동작이 커널 모드 전환의 대표적인 예다.

유저 모드와 커널 모드를 구분하고 메모리를 보호하는 것은 **운영체제가 아니라 CPU(프로세서)**가 담당한다.


커널 레벨 스레드 vs 유저 레벨 스레드

스레드 관리가 어느 영역에서 이뤄지느냐에 따라 두 모델로 나뉜다.

커널 레벨 스레드유저 레벨 스레드
스케줄링 주체커널 (스레드 단위)라이브러리 (커널은 프로세스만 인식)
스레드 정보 위치커널 영역유저 영역
모드 전환빈번하게 발생불필요

커널 레벨 스레드

  • 장점 — 커널이 직접 제공하므로 안전성과 다양한 기능이 보장된다.
  • 단점 — 스레드 관련 작업마다 유저 모드 → 커널 모드 전환이 빈번하게 발생해 성능 저하로 이어진다.

유저 레벨 스레드

  • 장점 — 커널은 스레드의 존재를 모른다. 오로지 유저 모드로만 동작하므로 모드 전환이 없어 성능이 좋다.
  • 단점 — 하나의 스레드가 시스템 호출로 커널에 의해 블로킹되면, 커널은 해당 프로세스 전체를 블로킹한다. 같은 프로세스 내의 다른 스레드들도 함께 멈춘다. 이를 해결하려 하면 프로그래밍이 복잡해지고 결과 예측이 어려워진다.

프로세스 vs 스레드

프로세스스레드
메모리 공유없음 (자식-부모도 별도)코드·데이터·힙 공유
통신 방식IPC 필요공유 메모리로 직접 접근
컨텍스트 스위칭 비용높음 (캐시 무효화)상대적으로 낮음 (캐시 재활용)
스케줄링 단위프로세스스레드 (커널 레벨 기준)

스레드 — 면접 질문 & 답변

기본 (5문항)

Q1. 프로세스와 스레드의 차이는 무엇인가요?

프로세스는 독립된 메모리 공간(코드/데이터/힙/스택)을 가지는 실행 단위입니다. 스레드는 하나의 프로세스 내에서 여러 실행 흐름을 두기 위한 모델로, 코드·데이터·힙은 같은 프로세스의 스레드끼리 공유하고 스택만 독립적으로 가집니다. 때문에 프로세스 간 통신에는 IPC가 필요하지만, 스레드 간에는 공유 메모리를 통해 직접 데이터를 주고받을 수 있습니다.

Q2. 스레드가 스택을 독립적으로 가지는 이유는 무엇인가요?

스택은 함수 호출 시 지역변수, 반환 주소, 매개변수 등을 저장하는 공간입니다. 각 스레드는 독립적인 실행 흐름을 가지므로, 서로의 함수 호출 상태가 섞이지 않으려면 스택이 분리되어 있어야 합니다. 스택은 독립적인 실행 흐름을 만들기 위한 최소 조건입니다.

Q3. 커널 레벨 스레드와 유저 레벨 스레드의 차이를 설명해 주세요.

커널 레벨 스레드는 스레드의 생성·스케줄링·관리가 커널 영역에서 이뤄집니다. 운영체제가 스레드의 존재를 알고 직접 스케줄링합니다. 유저 레벨 스레드는 커널이 스레드의 존재를 모르고, 라이브러리를 통해 유저 영역에서 스레드를 관리합니다. 커널 레벨은 안전하고 기능이 풍부하지만 모드 전환 비용이 따르고, 유저 레벨은 모드 전환이 없어 빠르지만 블로킹 문제가 있습니다.

Q4. 유저 모드와 커널 모드의 차이는 무엇인가요?

유저 모드에서는 프로세스가 커널 영역에 접근할 수 없습니다. 커널 모드에서는 모든 메모리 영역에 접근이 허용됩니다. 일반적으로 프로그램은 유저 모드로 실행되다가, 시스템 호출이나 타임슬라이스 만료 같은 상황에서 커널 모드로 전환됩니다. 이 모드 구분은 운영체제가 아니라 CPU(프로세서)가 하드웨어 수준에서 제공합니다.

Q5. 스레드 간 컨텍스트 스위칭이 프로세스 간 전환보다 가벼운 이유는 무엇인가요?

단순히 저장·복원해야 할 레지스터 수가 적어서라고 생각하기 쉽지만, 더 본질적인 이유는 캐시 히트 확률에 있습니다. 같은 프로세스 내의 스레드들은 코드·데이터·힙을 공유하기 때문에, 스레드 간 전환이 일어나도 캐시에 올라온 데이터가 그대로 유효합니다. 반면 프로세스 간 전환은 주소 공간 자체가 바뀌어 캐시가 무효화되고 대규모 캐시 미스가 발생합니다.

프로세스가 바뀌면 → CPU가 참조하는 페이지 테이블 자체가 교체됨 → 가상 주소 공간이 완전히 달라짐 → TLB(페이지 테이블 캐시)도 flush됨 → 캐시 미스 폭발

고난이도 (5문항)

Q6. 유저 레벨 스레드의 블로킹 문제를 구체적으로 설명하고, 이를 어떻게 완화할 수 있는지 말해 주세요.

유저 레벨 스레드 환경에서는 커널이 프로세스 단위로만 스케줄링합니다. 따라서 스레드 A가 시스템 호출을 통해 블로킹되면 커널은 해당 프로세스 전체를 블로킹 상태로 전환하고, 같은 프로세스 내의 스레드 B, C도 실행되지 못합니다. 이를 완화하는 방법으로는 블로킹 시스템 호출 대신 논블로킹(non-blocking) I/O를 사용하거나, jacketing 기법(블로킹 호출을 논블로킹으로 감싸는 래퍼)을 적용하는 방법이 있습니다. 다만 어떤 방법이든 구현이 복잡해지고 결과 예측이 어려워지는 단점이 있습니다.

Q7. 커널 레벨 스레드에서 모드 전환 비용이 발생하는 이유를 구체적으로 설명해 주세요.

커널 레벨 스레드는 생성·종료·동기화·스케줄링 같은 모든 스레드 관련 작업이 커널 영역에서 처리됩니다. 이 작업들을 요청할 때마다 유저 모드에서 커널 모드로의 전환이 발생합니다. 모드 전환 시에는 현재 레지스터 상태 저장, 커널 스택으로 전환, 권한 검증, 복귀 시 상태 복원 등의 과정이 수반됩니다. 이 과정이 스레드 연산마다 반복되므로 스레드가 많거나 동기화가 잦을수록 오버헤드가 누적됩니다.

Q8. 멀티스레드 환경에서 공유 메모리로 인해 발생할 수 있는 문제와 해결 방법을 설명해 주세요.

스레드들이 힙·데이터 영역을 공유하기 때문에 여러 스레드가 동시에 같은 데이터를 읽고 쓰면 경쟁 조건(race condition)이 발생할 수 있습니다. 예를 들어 두 스레드가 동시에 카운터를 증가시키면 갱신이 유실될 수 있습니다. 이를 해결하기 위해 뮤텍스(mutex), 세마포어(semaphore), 모니터(monitor) 같은 동기화 기법을 사용합니다. 다만 잘못 사용하면 교착 상태(deadlock)나 기아(starvation)가 발생할 수 있어 설계에 주의가 필요합니다.

Q9. 스레드를 지원하지 않는 운영체제에서의 스케줄링과 스레드를 지원하는 운영체제에서의 스케줄링의 차이를 설명해 주세요.

스레드를 지원하지 않는 운영체제는 스케줄링 단위가 프로세스입니다. CPU를 어느 프로세스에 할당할지만 결정합니다. 반면 커널 레벨 스레드를 지원하는 운영체제는 스케줄링 단위가 스레드입니다. 하나의 프로세스 내에 여러 스레드가 있으면 각 스레드가 독립적으로 CPU를 할당받을 수 있어, 멀티코어 환경에서 진정한 병렬 실행이 가능합니다. 유저 레벨 스레드 환경에서는 커널이 스레드를 모르므로 프로세스 단위로 스케줄링되고, 스레드 간 전환은 라이브러리가 알아서 처리합니다.

Q10. 같은 프로세스 내 스레드 간 컨텍스트 스위칭에서도 비용이 전혀 없지는 않습니다. 어떤 비용이 남아 있는지 설명해 주세요.

코드·데이터·힙을 공유하므로 캐시 재활용이 가능하지만, 비용이 완전히 사라지지는 않습니다. 각 스레드는 독립적인 스택을 가지므로 스택 포인터와 스택 관련 레지스터는 저장·복원해야 합니다. 또한 프로그램 카운터(PC), 범용 레지스터 등 실행 상태 정보도 여전히 교체가 필요합니다. 스레드가 서로 다른 메모리 영역을 집중적으로 사용했다면 해당 캐시 라인이 무효화되어 캐시 미스가 일부 발생할 수도 있습니다. 프로세스 전환에 비해 훨씬 가볍지만, 비용이 0은 아닙니다.