In Veritate Libertas

The Restricted
Section

A collection of spells,
experiments, and forbidden knowledge.

Study/[ OS ] | 2026. 6. 20. 23:53

#03 프로세스와 스레드

728x90

프로세스와 스레드 — 면접 단골인데 막상 설명하기 어려운 것들

"프로세스랑 스레드 차이 설명해보세요"가 면접 단골 질문인건 알지? 막상 아는 것 같은데 정확하게 말하려면 입이 잘 안 떨어지거든. 이번에 제대로 정리해봤어.


프로세스(Process)란?

메모리에 올라가서 CPU 자원을 할당받아 실행 중인 프로그램이야.

"프로그램"이랑 "프로세스"를 헷갈리기 쉬운데, 프로그램은 디스크에 저장된 실행 파일이고, 그 파일이 실행되어 메모리에 올라간 상태가 프로세스야. 같은 프로그램을 두 번 실행하면 프로세스가 두 개 생겨.

프로세스는 메모리 안에서 네 영역으로 나뉘어.

┌──────────────────┐ 높은 주소
│    Stack 영역    │ ← 함수 호출 시 생성, 리턴 주소·지역변수 저장
│       ↓↑         │   동적 영역 (런타임에 크기 변동)
│    Heap 영역     │ ← 동적 할당 데이터 (new, malloc 등)
├──────────────────┤
│    Data 영역     │ ← 전역변수, static 변수 (정적 영역)
├──────────────────┤
│    Code 영역     │ ← 프로그래머가 작성한 코드 (정적 영역)
└──────────────────┘ 낮은 주소

Code 영역과 Data 영역은 정적 영역 — 선언할 때 크기가 결정되고 바뀌지 않아.

Stack 영역과 Heap 영역은 동적 영역 — 실행 중에 크기가 늘었다 줄었다 해.

여기서 의문이 생겨. "그럼 Stack이랑 Heap이 충돌하면 어떻게 돼?" — 실제로 Stack은 높은 주소에서 아래로 자라고, Heap은 낮은 주소에서 위로 자라. 둘이 만나는 순간 Stack Overflow나 Heap Overflow가 발생해. C/C++에서 재귀 함수를 너무 깊게 호출하다가 Stack Overflow 나는 게 이 이유야.

중요한 점 하나 — 스택과 힙 영역은 서로 다른 프로세스 간에는 메모리 공간 접근이 허용되지 않아. 프로세스 A가 프로세스 B의 메모리를 직접 읽거나 쓸 수 없어. OS가 이걸 막아. 이게 프로세스 격리(Process Isolation)야.


스레드(Thread)란?

프로세스 내에서 실행되는 흐름의 단위야.

하나의 프로세스는 반드시 하나 이상의 스레드를 가져. 처음 생성되는 스레드를 메인 스레드라고 해.

스레드는 프로세스의 메모리를 공유해. 정확히는 이래.

프로세스
├── Code 영역  ← 스레드 간 공유
├── Data 영역  ← 스레드 간 공유
├── Heap 영역  ← 스레드 간 공유
├── Stack (Thread 1) ← Thread 1 전용
├── Stack (Thread 2) ← Thread 2 전용
├── ...
└── Stack (Thread n) ← Thread n 전용

Stack만 따로 가지고 나머지(Code, Data, Heap)는 공유해. Stack이 따로 있는 이유는 각 스레드가 독립적인 함수 호출 흐름을 가져야 하기 때문이야.

같은 Heap을 공유한다는 게 스레드의 강점이자 약점이야. 데이터 공유가 쉬운 대신, 동시에 같은 데이터에 접근하면 충돌이 생겨. 이게 나중에 다룰 동기화(Synchronization) 문제야.


멀티태스킹(Multitasking)

OS가 CPU 자원(시간)을 프로세스 또는 스레드 간에 나눠서 여러 작업을 동시에 처리하는 것처럼 보이게 하는 기법이야.

싱글 코어 CPU는 한 번에 하나의 작업만 할 수 있어. 근데 여러 프로그램이 동시에 실행되는 것처럼 보이는 건, CPU가 아주 빠르게 작업을 번갈아 가며 처리하기 때문이야. 이때 작업을 전환하는 게 컨텍스트 스위칭(Context Switching)이야.


멀티 프로세스 vs 멀티 스레드

같은 작업을 여러 프로세스로 나눌 수도 있고, 여러 스레드로 나눌 수도 있어. 둘의 차이가 뭔지 비교해보면 이래.

멀티 프로세스

하나의 애플리케이션을 여러 개의 프로세스로 구성해 각 프로세스가 하나의 작업을 처리하게 하는 거야

  • 안정성이 좋아: 자식 프로세스 하나에 문제가 생겨도 다른 프로세스에 영향이 없어. Chrome이 탭마다 프로세스를 분리하는 이유야 — 탭 하나가 뻗어도 브라우저 전체가 죽지 않아
  • 프로세스 간 통신이 복잡해: 프로세스는 메모리를 공유하지 않으니까 데이터를 주고받으려면 IPC를 써야 해 (IPC는 아래에서 설명해줄게)
  • 메모리 사용량이 많아: 각 프로세스가 독립적인 메모리 공간을 가지니까 많겠지?
  • 컨텍스트 스위칭 비용이 커: 프로세스 전환 시 메모리 주소 공간도 함께 바꿔야 해. 그래서 성능 저하의 우려도 있어!

멀티 스레드

하나의 프로그램을 여러 스레드로 구성해 각 스레드가 작업을 처리하게 하는 거야

  • 응답성이 좋아: 자식 스레드 하나가 오래 걸리는 작업을 해도 그 동안 다른 스레드가 계속 실행돼
  • 자원 공유가 쉬워: 부모 프로세스는 Heap, Code, Data를 공유하니까 데이터 전달이 간단해. 스레드 간 통신 비용이 낮아
  • 컨텍스트 스위칭 비용이 작아: 같은 프로세스 내 스레드 전환은 메모리 주소 공간을 바꿀 필요가 없어서 빨라.
  • 디버깅이 어려워: 여러 스레드가 동시에 실행되니까 타이밍에 따라 버그가 재현이 안 될 수 있어
  • 동기화 문제: 공유 메모리에 동시 접근하면 Race Condition이 발생할 수 있어
  • 한 스레드의 오류가 전체 프로세스에 영향: 공유 메모리를 쓰다 보니 잘못된 접근이 전체 프로세스를 죽일 수 있어
  멀티 프로세스 멀티 스레드
메모리 독립적 (많이 씀) 공유 (적게 씀)
통신 IPC 필요 (복잡) 공유 메모리 (쉬움)
안정성 높음 (격리) 낮음 (하나가 죽으면 전체)
컨텍스트 스위칭 비용 높음 비용 낮음
디버깅 비교적 쉬움 어려움

위에서 나온 용어들 중 이해 안될만 한 것들 설명 해줄게.

IPC(Inter-Process Communication)

프로세스는 서로 메모리를 공유하지 않아서 통신하려면 IPC가 필요해. 주로 분류하는 주요 방식은 이래.

파이프(Pipe)

두 프로세스를 연결하는 단방향 채널이야. 한쪽이 쓰면 다른 쪽이 읽어. Linux 터미널에서 자주 쓰는 |가 파이프야.

cat file.txt | grep "keyword"
# cat의 출력을 grep의 입력으로 파이프 연결

소켓(Socket)

네트워크 기반의 IPC. 같은 머신 안이나 다른 머신의 프로세스와도 통신할 수 있어. HTTP 통신이 소켓 기반이야.

공유 메모리(Shared Memory)

두 프로세스가 같은 메모리 영역을 접근하도록 설정하는 방식이야. 데이터를 복사하지 않고 직접 접근하니까 IPC 중 제일 빠르지만 동기화를 직접 관리해야 해.

메시지 큐(Message Queue)

프로세스 간에 메시지를 비동기적으로 주고받는 큐야. 생산자-소비자 패턴에서 많이 써. Kafka 같은 메시지 브로커가 이 개념을 확장한 거야.


컨텍스트 스위칭(Context Switching)

CPU가 한 프로세스(또는 스레드)에서 다른 것으로 전환하는 과정이야.

1. 현재 실행 중인 프로세스(P1) 상태를 PCB1에 저장
   (Program Counter, 레지스터, 스택 포인터 등)
2. 스케줄러가 다음에 실행할 프로세스(P2) 선택
3. PCB2에서 P2의 상태를 CPU 레지스터로 복원
4. P2 실행 재개

PCB(Process Control Block)는 프로세스의 "이력서"야. OS가 프로세스마다 PCB를 만들어서 상태를 기록해둬. 컨텍스트 스위칭이 일어날 때 PCB에 현재 상태를 저장하고, 다음 프로세스의 PCB를 불러와.

컨텍스트 스위칭의 비용

컨텍스트 스위칭은 그 자체로 순수한 오버헤드야. 전환하는 동안 CPU는 실제 작업을 못 해. 비용이 생기는 이유는 여러 가지야. 

  • PCB 저장/복원 시간
  • TLB(Translation Lookaside Buffer) 플러시 — 프로세스가 바뀌면 메모리 주소 변환 캐시를 비워야 해
  • 캐시 미스 증가 — 새 프로세스에 맞는 데이터로 캐시가 다시 채워져야 해

프로세스 간 스위칭이 스레드 간 스위칭보다 비용이 더 비싼 이유가 있어. 같은 프로세스 내 스레드 전환은 메모리 주소 공간을 바꿀 필요가 없거든. 스레드는 같은 가상 메모리 맵을 공유하니까 TLB 플러시도 없어.

스위칭이 너무 자주 일어나면 스래싱(Thrashing)이 발생해 — CPU가 실제 작업보다 전환하는 데 더 많은 시간을 쓰는 현상이야. 너무 많은 스레드를 만드는 것도 오버헤드의 원인이야.


Thread Safe란?

여러 스레드가 동시에 같은 자원에 접근해도 결과가 항상 올바른 상태 — 이걸 Thread Safe하다고 해.

멀티 스레드 환경에선 두 스레드가 동시에 같은 변수를 수정하려 들 수 있어. 예를 들어 count = 0인 변수에 두 스레드가 동시에 count++를 하면 결과가 2가 아닌 1이 될 수 있어. 이게 Race Condition이야.

이걸 막는 게 동기화(Synchronization)인데, 나중에 뮤텍스(Mutex), 세마포어(Semaphore)랑 같이 다룰게.


아래는 면접 대비 핵심 질문을 정리해뒀어.

더보기

Q. 프로세스와 스레드의 차이는? 프로세스는 OS로부터 자원(메모리, CPU)을 할당받는 독립적인 실행 단위. 스레드는 프로세스 내에서 실제 작업을 수행하는 실행 단위로, 같은 프로세스 안의 스레드들은 Code, Data, Heap을 공유하고 Stack만 독립적으로 가져.

Q. 멀티 프로세스와 멀티 스레드의 차이는? 멀티 프로세스는 독립 메모리라 안정성이 높지만 IPC가 필요하고 컨텍스트 스위칭 비용이 커. 멀티 스레드는 메모리 공유라 통신이 쉽고 빠르지만 동기화 문제와 한 스레드 오류가 전체에 영향을 줄 수 있어.

Q. 컨텍스트 스위칭이란? CPU가 실행 중인 프로세스/스레드를 전환할 때 현재 상태를 PCB에 저장하고 다음 것의 상태를 복원하는 과정이야. 전환 중엔 CPU가 실제 작업을 못 해서 순수한 오버헤드야.

Q. 프로세스 간 컨텍스트 스위칭이 스레드 간보다 비싼 이유는? 프로세스 전환 시엔 메모리 주소 공간이 달라서 TLB 플러시와 캐시 재적재가 필요해. 같은 프로세스 내 스레드 전환은 가상 메모리 맵을 공유해서 이 비용이 없어.

Q. Thread Safe란? 여러 스레드가 동시에 같은 자원에 접근해도 항상 올바른 결과를 내는 상태. Race Condition을 막기 위해 동기화 기법(Mutex, Semaphore 등)을 사용해.

Q. IPC란 무엇이고 어떤 방식이 있나? 프로세스 간 통신 방법. 파이프(단방향 채널), 소켓(네트워크 기반), 공유 메모리(가장 빠름), 메시지 큐(비동기)가 대표적이야.


오늘 공부는 여기서 끝! 다음엔 CPU 스케줄링 알고리즘 파볼게.

728x90

'Study > [ OS ]' 카테고리의 다른 글

#06 시스템콜 System Call  (0) 2026.06.24
#05 인터럽트 Interrupt  (0) 2026.06.23
#04 CPU 스케줄링 알고리즘  (0) 2026.06.22
#02 메모리 계층  (0) 2026.06.18
#01 운영체제와 컴퓨터  (0) 2026.06.18
흐이서

흐이서

Writer

공순이 흐이서