Skip to content

Chapter 03. 프로세스와 스레드

운영체제가 관리하는 두 가지 핵심 실행 단위인 **프로세스(Process)**와 **스레드(Thread)**를 깊이 있게 살펴본다. CPU와 메모리라는 전산 자원이 어떻게 할당되는지, 프로세스의 생성과 상태 전이, 문맥 교환(Context Switching), 그리고 멀티스레딩(Multithreading)까지 다룬다.


3.1 전산 자원의 두 축: CPU와 메모리

컴퓨터의 핵심 자원

컴퓨터가 프로그램을 실행할 때 사용하는 핵심 자원은 딱 두 가지다.

자원역할할당 단위
CPU (Central Processing Unit)명령어를 해석하고 연산을 수행스레드(Thread) 단위로 사용
RAM (Random Access Memory)실행 중인 프로그램의 데이터를 저장프로세스(Process) 단위로 할당

이 두 자원의 할당 방식 차이가 프로세스와 스레드를 이해하는 핵심 열쇠다.

자원 할당의 원칙

운영체제는 다음과 같은 원칙으로 자원을 관리한다.

  1. **가상 메모리 공간(Virtual Memory Space, VMS)**은 프로세스 단위로 할당된다.
  2. CPU 실행 시간스레드 단위로 배분된다.
    • Windows: 스레드를 스케줄링 단위로 사용
    • Unix/Linux: 전통적으로 프로세스를 스케줄링 단위로 사용 (현대 리눅스에서는 스레드도 경량 프로세스로 취급)
  3. **권한(접근 제어)**은 프로세스에게 부여된다. 그 안의 스레드들은 프로세스의 권한을 공유한다.

프로세스 간 메모리 격리

가상 메모리 공간은 프로세스마다 완전히 독립적이다. 프로세스 A가 사용하는 메모리 공간에 프로세스 B는 절대 접근할 수 없다. 이것이 운영체제가 보장하는 **메모리 보호(Memory Protection)**다.

반면, 같은 프로세스 안의 스레드들은 그 프로세스의 가상 메모리 공간을 자유롭게 공유한다. 코드 영역, 데이터 영역, 힙(Heap) 영역 모두 함께 사용할 수 있다.

비유: 집과 사람

프로세스와 스레드의 관계를 집과 거기 사는 사람에 비유하면 이해가 쉽다.

비유실제설명
프로세스 (Process)독립적인 공간을 가진다. 다른 집 사람이 마음대로 들어올 수 없다.
사는 사람스레드 (Thread)집 안의 거실, 주방, 화장실을 자유롭게 사용한다.
집 열쇠/권한접근 제어 (Access Control)집에 부여된 권한이고, 거기 사는 사람들이 공유한다.
집 주소가상 메모리 공간 (VMS)각 집마다 고유한 주소가 있고, 다른 집과 구별된다.

핵심: CPU는 스레드가 사용하고, 메모리는 프로세스가 소유한다. 프로세스는 독립된 집이고, 스레드는 그 집에 사는 사람이다.


3.2 프로세스 제어 블록 (PCB - Process Control Block)

PCB란?

운영체제가 프로세스를 관리하기 위해 사용하는 **자료구조(Data Structure)**다. 프로세스 하나가 생성될 때마다 OS 커널 내부에 해당 프로세스의 PCB가 하나 만들어진다.

PCB에는 프로세스의 모든 관리 정보가 담겨 있다. 마치 회사에서 직원 한 명당 인사 카드를 만들어 관리하는 것과 같다.

PCB에 포함되는 정보

항목영문설명
프로세스 IDPID (Process ID)양의 정수. 프로세스를 식별하는 고유한 번호. 시스템 전체에서 유일하다.
프로그램 카운터PC (Program Counter)현재 실행 중인(또는 다음에 실행할) 기계어 명령의 메모리 주소. CPU가 "지금 어디까지 읽었는지"를 기록한다.
레지스터 정보Register SetCPU 레지스터들의 상태를 백업해둔 값. 문맥 교환 시 저장/복원에 사용된다.
프로세스 상태Process State현재 상태 (Ready, Running, Waiting 등)
메모리 관련 정보Memory Info가상 메모리 공간의 시작 주소, 페이지 테이블 정보 등
스케줄링 정보Scheduling Info우선순위(Priority), CPU 사용 시간 등
I/O 상태 정보I/O Status열린 파일 목록, 할당된 I/O 장치 정보

프로세스 메모리 구조 (Memory Layout)

프로세스에게 할당된 가상 메모리 공간은 다음과 같은 영역으로 나뉜다.

영역저장 내용특징
Stack지역 변수, 함수 매개변수, 복귀 주소함수 호출 시 자동 생성, 리턴 시 자동 해제. 위에서 아래로 성장.
Heapmalloc(), new로 동적 할당한 메모리프로그래머가 직접 할당/해제 관리. 아래에서 위로 성장.
Data(Static)전역 변수, 정적 변수, 문자열 상수프로그램 시작 시 할당, 종료 시 해제. BSS(미초기화) + Data(초기화) 세그먼트.
Code(Text)컴파일된 기계어 명령 코드읽기 전용(Read-Only). 실행 중 변경 불가.

Stack과 Heap이 서로 반대 방향으로 성장하는 이유는, 한정된 메모리 공간을 최대한 효율적으로 사용하기 위해서다. 두 영역이 같은 방향으로 자라면, 한쪽이 남아도 다른 쪽이 부족할 수 있다. 반대 방향이면 남은 공간을 양쪽이 공유한다.

TCB (Thread Control Block)

PCB가 프로세스를 관리하는 자료구조라면, **TCB(Thread Control Block)**는 스레드를 관리하는 자료구조다.

TCB에는 스레드 고유의 정보만 들어간다.

PCB (프로세스 고유)TCB (스레드 고유)
PID스레드 ID (TID)
가상 메모리 공간 정보프로그램 카운터 (PC)
열린 파일 목록레지스터 상태
접근 권한 정보스레드 고유 스택 포인터
프로세스 상태스레드 상태 (Ready/Running/Waiting)

같은 프로세스에 속한 스레드들은 PCB의 메모리 정보, 파일 정보, 권한 정보를 공유하고, TCB의 PC, 레지스터, 스택만 독립적으로 유지한다.


3.3 프로세스 상태 전이

프로세스의 라이프사이클

프로세스는 생성부터 종료까지 여러 **상태(State)**를 거친다. 이 상태 변화를 **상태 전이(State Transition)**라고 부른다.

상태영문설명
생성New프로세스가 막 생성된 상태. PCB 할당, 메모리 적재 등 초기화 진행 중.
준비Ready실행 준비 완료. CPU만 할당받으면 바로 실행할 수 있는 상태.
실행RunningCPU를 할당받아 실제로 명령을 수행 중인 상태.
대기Waiting (Blocked)I/O 요청 등으로 CPU를 사용할 수 없어 기다리는 상태.
완료Terminated실행이 끝난 상태. 자원 회수 대기 중.

Ready Queue와 디스패치(Dispatch)

Ready Queue는 CPU 할당을 기다리는 프로세스들이 줄을 서 있는 대기열(Queue) 자료구조다.

**디스패치(Dispatch)**란 OS 스케줄러가 Ready Queue에서 프로세스 하나를 선택해서 꺼내 CPU에 할당하는 동작을 말한다.

  • 디스패처(Dispatcher) = 운행원, 관리원이라는 뜻
  • "줄 서 있는 사람들 중에서 한 명을 골라 보내는 것"

비유: 마치 허준 드라마의 명대사 **"줄을 서시오!"**처럼, 프로세스들은 CPU를 사용하기 위해 줄(Queue)을 서야 한다. OS가 순서대로(또는 우선순위에 따라) 하나씩 불러낸다.

시분할 시스템 (Time-Sharing System)

현대 컴퓨터에는 보통 4~16개의 CPU 코어가 있다. 하지만 동시에 실행되어야 하는 스레드는 수천 개에 달한다.

예를 들어 2000개의 스레드8개의 코어를 사용해야 한다면?

운영체제는 시분할(Time-sharing) 방식으로 해결한다.

  1. 각 스레드에게 아주 짧은 시간(Time Quantum, 보통 수 ms ~ 수십 ms)만큼 CPU를 할당한다.
  2. 시간이 다 되면 강제로 CPU를 회수하고, 다음 스레드에게 넘긴다.
  3. 이 전환이 매우 빠르게 일어나므로, 인간의 눈에는 모든 프로그램이 동시에 실행되는 것처럼 보인다.

입출력과 대기 상태

프로세스가 I/O(입출력) 요청을 하면 어떻게 될까? 두 가지 방식이 있다.

방식설명프로세스 상태
Blocking I/OI/O 요청 후 완료될 때까지 기다린다Running -> Waiting 상태로 전환
Non-blocking I/OI/O 요청만 보내고 바로 돌아온다Running 상태 유지

Blocking I/O에서는 I/O가 완료될 때까지 프로세스가 Waiting 상태에 머무르므로 CPU를 사용하지 않는다. I/O가 끝나면 다시 Ready 상태로 돌아가 Queue에 합류한다.

Sleep vs Suspend

프로세스가 Ready Queue에서 빠지는 경우가 두 가지 더 있다. **자발적 이탈(Sleep)**과 **강제 이탈(Suspend)**이다.

Sleep (휴식 상태) - "나 좀 잘게"

Sleep은 프로세스가 스스로 일정 시간 동안 CPU를 사용하지 않겠다고 선언하는 것이다.

sleep(10ms)  // "10밀리초 동안 쉴게"

동작 과정:

  1. 프로세스가 sleep(10ms) 호출
  2. Ready Queue에서 자발적으로 이탈
  3. 10ms가 지나면 Ready Queue 맨 뒤에 다시 합류
  4. 자기 차례가 올 때까지 다시 대기

실제 대기 시간 = 지정 시간(10ms) + 알파(alpha)

이 "알파"는 Ready Queue 앞에 줄 서 있는 프로세스들이 처리되는 시간이다. 큐에 몇 개의 프로세스가 있는지, 각각 얼마나 CPU를 사용하는지에 따라 달라지므로 예측이 불가능하다.

이 예측 불가능한 "알파" 값을 이용해 **난수(Random Number)**를 생성하는 기법도 있을 정도다. 그만큼 시스템 상황에 따라 변동이 크다.

Suspend (보류 상태) - "너 좀 비켜봐"

Suspend는 프로세스 외부의 요인에 의해 강제로 Queue에서 빠지는 것이다.

발생 원인:

  • 스왑(Swap) 발생: 메모리 부족으로 OS가 프로세스를 디스크로 내보냄
  • 오류 발생: 프로세스에 문제가 생겨 OS가 강제 중단
  • 관리자 개입: 시스템 관리자가 의도적으로 프로세스를 중단

Suspend된 프로세스도 재진입 시 Queue 맨 뒤에 합류하므로, 역시 "알파" 시간이 발생한다.

구분SleepSuspend
주체프로세스 자신 (자발적)OS 또는 외부 (강제적)
비유"나 좀 잘게""너 좀 비켜봐"
원인프로그램 내 sleep() 호출메모리 부족, 오류, 관리자 개입
재진입지정 시간 후 Ready Queue 맨 뒤원인 해소 후 Ready Queue 맨 뒤

프로세스 상태 전이 다이어그램


3.4 문맥 교환 (Context Switching)

문맥(Context)이란?

프로세스의 실행 흐름 상태 전체를 **문맥(Context)**이라고 한다. 구체적으로는 다음 정보를 포함한다.

  • 프로그램 카운터(PC): 어디까지 실행했는지
  • CPU 레지스터 값들: 연산 중간 결과
  • 프로세스 상태: Ready, Running 등
  • 메모리 관리 정보: 페이지 테이블 등

문맥 교환이란?

한 프로세스에서 다른 프로세스로 CPU 제어권이 넘어가는 과정을 **문맥 교환(Context Switching)**이라고 한다.

시분할 시스템에서 타임 퀀텀(Time Quantum)이 만료되면, OS는 현재 프로세스를 중단하고 다음 프로세스를 실행해야 한다. 이때 반드시 문맥 교환이 발생한다.

문맥 교환의 과정

단계별로 정리하면 다음과 같다.

단계동작설명
1단계현재 프로세스 상태 저장프로세스 A의 PC, 레지스터 값을 A의 PCB에 저장
2단계다음 프로세스 선택OS 스케줄러가 Ready Queue에서 프로세스 B를 선택 (디스패치)
3단계새 프로세스 상태 복원프로세스 B의 PCB에서 PC, 레지스터 값을 CPU에 로드
4단계실행 시작프로세스 B가 이전에 멈춘 지점부터 실행 재개

문맥 교환의 비용

문맥 교환은 **순수 오버헤드(Overhead)**다. 교환이 일어나는 동안에는 어떤 프로세스도 유용한 작업을 하지 않는다. 그래서 문맥 교환이 너무 자주 일어나면 시스템 성능이 떨어진다.

비유: 고속도로에서 차선 변경을 생각해보자. 차선을 바꾸는 동안에는 앞으로 나아가지 못하고, 핸들을 돌리고 미러를 확인하는 데 시간을 소비한다. 차선 변경(문맥 교환)을 너무 자주 하면, 정작 목적지까지 가는 속도(실제 연산)는 느려진다. 하지만 차선 변경 없이는 여러 차(프로세스)가 도로(CPU)를 공유할 수 없다.


3.5 프로세스 생성: fork() vs exec()

프로세스 생성이 복잡한 이유

새 프로세스를 생성하려면 다음 작업이 필요하다.

  1. 가상 메모리 공간(VMS) 할당 - 페이지 테이블 생성, 메모리 매핑
  2. PCB 생성 - 프로세스 관리 정보 초기화
  3. 실행 파일 로딩 - 디스크에서 코드/데이터를 메모리에 적재
  4. 스택/힙 초기화 - 실행에 필요한 메모리 영역 설정

이 모든 작업을 처음부터 하는 것은 매우 비용이 큰 작업이다.

부모-자식 관계

프로세스 생성에는 항상 부모-자식 관계가 존재한다.

용어설명
부모 프로세스 (Parent Process)새 프로세스를 만드는 원래 프로세스
자식 프로세스 (Child Process)새로 만들어진 프로세스

실행 파일 구조

프로그램이 디스크에 저장되어 있을 때의 형식은 운영체제마다 다르다.

OS형식정식 명칭
WindowsPEPortable Executable
Unix/LinuxELFExecutable and Linkable Format

두 형식 모두 기본 구조는 비슷하다: 헤더(Header) + 섹션(Section)(Code/Text, Data 등)

fork() - 통째로 복사

fork()부모 프로세스를 통째로 복사하여 새 프로세스를 만드는 시스템 콜이다.

복사되는 것:

  • 가상 메모리 공간 (VMS) 전체
  • PCB (새 PID가 부여됨)
  • 환경변수
  • 열린 파일 디스크립터
  • 코드, 데이터, 힙, 스택 영역 전부

결과: 프로세스가 2개 존재하게 된다 (부모 + 자식).

fork() 호출 전: [부모 프로세스] 1개
fork() 호출 후: [부모 프로세스] + [자식 프로세스] = 2개

왜 처음부터 새로 만들지 않고 복사하는가? 이미 존재하는 프로세스를 복사하는 것이 처음부터 새로 VMS를 구성하고, PCB를 세팅하고, 실행 파일을 로딩하는 것보다 훨씬 빠르기 때문이다. 현대 OS는 COW(Copy-On-Write) 기법을 사용하여 실제 메모리 복사를 최대한 지연시키기도 한다.

exec() - 덮어쓰기

exec()는 기존 프로세스의 메모리 공간을 새로운 프로그램의 코드로 덮어쓰는 시스템 콜이다.

핵심: VMS와 PCB를 새로 만들지 않는다. 기존 것을 재활용한다.

결과: 프로세스가 1개 그대로다 (부모가 새 프로그램으로 변신).

exec() 호출 전: [부모 프로세스(프로그램 A 실행 중)] 1개
exec() 호출 후: [같은 프로세스(프로그램 B로 교체됨)] 1개

exec()fork()보다 훨씬 효율적이다. 메모리를 복사할 필요 없이, 코드/데이터 영역만 새 프로그램으로 교체하면 되기 때문이다.

fork() + exec() 조합

Unix/Linux에서 새 프로그램을 실행할 때 가장 일반적인 패턴은 **fork() 후 exec()**이다.

  1. fork()로 자식 프로세스 생성 (부모 복사)
  2. 자식 프로세스에서 exec()로 새 프로그램 코드를 로딩
  3. 부모 프로세스는 wait()로 자식이 끝나기를 대기

Windows: CreateProcess()

Windows에서는 fork() + exec()를 따로 하지 않고, CreateProcess() 한 번의 호출로 새 프로세스를 생성한다.

  • CreateProcess() = fork + exec을 한 번에 수행
  • WaitForSingleObject() = Unix의 wait()에 해당. 자식 프로세스 종료 대기.

fork vs exec 비교 흐름도

항목fork()exec()CreateProcess() (Windows)
동작부모를 통째로 복사코드를 덮어쓰기fork + exec 한 번에
결과 프로세스 수2개 (부모 + 자식)1개 (같은 프로세스)2개 (부모 + 자식)
VMS복사 생성재활용새로 생성
PCB복사 생성 (새 PID)재활용 (같은 PID)새로 생성
효율성exec보다 무거움fork보다 가벼움중간
종료 대기wait()-WaitForSingleObject()

3.6 멀티스레딩 (Multithreading)

멀티스레딩이란?

하나의 프로세스 안에 여러 스레드가 존재하는 것을 **멀티스레딩(Multithreading)**이라고 한다.

공유하는 것:

  • 가상 메모리 공간(VMS) 전체: 코드(Code), 데이터(Data), 힙(Heap) 영역
  • 열린 파일, 권한 정보

독립적인 것:

  • 각자의 스택(Stack)
  • 각자의 프로그램 카운터(PC)
  • 각자의 레지스터 상태

멀티프로세싱 vs 멀티스레딩

항목멀티프로세싱 (Multi-Processing)멀티스레딩 (Multi-Threading)
메모리각 프로세스가 독립 VMS 보유하나의 VMS를 스레드들이 공유
자원 효율메모리 중복 → 낭비메모리 공유 → 효율적
안전성프로세스 간 격리 → 안전공유 자원 접근 → 동기화 문제
통신IPC(Inter-Process Communication) 필요 → 복잡공유 메모리로 직접 통신 → 간단
생성 비용VMS 새로 할당 → 비용 큼스택만 추가 할당 → 비용 작음
장애 격리하나가 죽어도 다른 프로세스 영향 없음하나가 죽으면 전체 프로세스 종료 위험

비유: 오피스텔 vs 한 집

이 차이를 주거 형태에 비유하면 직관적으로 이해할 수 있다.

멀티프로세싱 = 오피스텔 각방

[101호 - 사람 A]  [102호 - 사람 B]  [103호 - 사람 C]
  화장실 O           화장실 O           화장실 O
  부엌 O             부엌 O             부엌 O
  냉장고 O           냉장고 O           냉장고 O
  • 각자 독립된 공간독립된 시설을 가진다.
  • 비용이 많이 들지만(방마다 화장실, 부엌, 냉장고), 서로 방해하지 않는다.
  • 101호에 문제가 생겨도 102호, 103호는 영향 없다.

멀티스레딩 = 한 집에 여러 사람

[집 한 채]
  사람 A, 사람 B, 사람 C
  공유 화장실 1개
  공유 부엌 1개
  공유 냉장고 1개
  • 하나의 공간에 여러 사람이 산다.
  • 비용이 적게 들지만(시설 공유), 경쟁과 충돌이 발생한다.
  • 화장실을 동시에 사용하려 하면? → 병목현상(Bottleneck)
  • 냉장고에서 내 음식을 다른 사람이 먹으면? → 데이터 무결성 문제
  • 한 사람이 가스밸브를 잘못 열면 집 전체가 위험 → 장애 전파

결론: 멀티스레딩은 자원을 아낄 수 있지만, 공유 자원에 대한 동기화(Synchronization) 문제를 반드시 해결해야 한다. 이것이 바로 운영체제에서 동기화와 **교착 상태(Deadlock)**를 배우는 이유다.


핵심 정리

주요 용어 정리

용어영문설명
프로세스Process실행 중인 프로그램. 독립된 가상 메모리 공간(VMS)을 소유한다.
스레드Thread프로세스 안의 실행 단위. CPU 스케줄링의 기본 단위이며 프로세스의 메모리를 공유한다.
PCBProcess Control BlockOS가 프로세스를 관리하기 위한 자료구조. PID, PC, 레지스터, 메모리 정보 등을 포함한다.
TCBThread Control Block스레드 관리용 자료구조. TID, PC, 레지스터, 스택 포인터를 포함한다.
Ready QueueReady QueueCPU 할당을 기다리는 프로세스들의 대기열.
디스패치DispatchReady Queue에서 프로세스를 선택해 CPU에 할당하는 동작.
문맥 교환Context Switching실행 중인 프로세스를 중단하고 다른 프로세스로 CPU 제어를 넘기는 과정.
시분할Time-SharingCPU 시간을 작은 단위로 쪼개어 여러 프로세스에게 돌아가며 할당하는 방식.
fork()fork()부모 프로세스를 통째로 복사하여 자식 프로세스를 생성하는 시스템 콜.
exec()exec()기존 프로세스의 코드를 새 프로그램으로 덮어쓰는 시스템 콜.
SleepSleep프로세스가 자발적으로 일정 시간 CPU 사용을 포기하는 것.
SuspendSuspend외부 요인에 의해 프로세스가 강제로 중단되는 것.
멀티프로세싱Multi-Processing여러 프로세스가 독립적인 VMS를 가지고 동시에 실행되는 것.
멀티스레딩Multi-Threading하나의 프로세스 안에서 여러 스레드가 VMS를 공유하며 실행되는 것.

5줄 요약

  1. CPU는 스레드 단위, 메모리는 프로세스 단위로 할당된다. 프로세스는 독립된 집이고 스레드는 그 안에 사는 사람이다.
  2. **PCB(Process Control Block)**는 OS가 프로세스를 관리하는 핵심 자료구조이며, 프로세스의 메모리는 Stack, Heap, Data, Code 네 영역으로 나뉜다.
  3. 프로세스는 생성 -> 준비 -> 실행 -> 대기 -> 완료 상태를 거치며, Ready Queue에서 디스패치를 통해 CPU를 할당받고, Sleep(자발적)이나 Suspend(강제적)로 Queue에서 이탈할 수 있다.
  4. **문맥 교환(Context Switching)**은 CPU 제어권이 프로세스 간 전환되는 과정으로, PCB에 상태를 저장/복원하며 순수 오버헤드가 발생한다. **fork()**는 복사, **exec()**는 덮어쓰기 방식으로 프로세스를 생성한다.
  5. 멀티스레딩은 자원 효율적이지만 공유 자원에 대한 동기화 문제가 발생하고, 멀티프로세싱은 안전하지만 자원이 낭비된다. 이 트레이드오프를 이해하는 것이 핵심이다.