운영체제를 공부하다 보면 프로세스(Process) 와 스레드(Thread) 는 거의 항상 같이 나온다.
그런데 막상 이 둘을 설명하려고 하면 생각보다 헷갈리는 부분이 많다.
예를 들면 이런 질문들이다.
이번 글은 이런 질문들에 답하면서
프로세스와 스레드의 구조를 정리해 보았다.
프로세스는 실행 중인 프로그램이라고 보면 된다.
디스크에 저장되어 있던 프로그램이 메모리에 올라와 실제로 실행되기 시작하면
그 상태를 프로세스라고 부른다.
예를 들면
이 각각이 하나의 프로세스가 된다.
여기서 중요한 점은
프로세스는 단순히 실행 중이라는 의미만 가지는 것이 아니라
자기만의 독립적인 메모리 공간(Address Space) 을 가진다는 점이다.
겉으로는
Process A Memory: 0x0000 ~ 0xFFFF
Process B Memory: 0x0000 ~ 0xFFFF
처럼 비슷하게 보일 수 있지만
실제로는 서로 완전히 분리된 공간이다.
그래서 서로 다른 프로세스는
기본적으로 서로의 메모리에 직접 접근할 수 없다.
스레드는 프로세스 안에서 실제로 실행되는 흐름이다.
하나의 프로세스는 하나 이상의 스레드를 가질 수 있다.
Process
├ Thread
├ Thread
└ Thread
여기서 중요한 건
CPU가 실제로 실행하는 대상은 스레드라는 점이다.
정리하면
즉, 프로세스가 집이라면 스레드는 그 집 안에서 실제로 움직이는 사람에 더 가깝다.
보통 하나의 프로세스는 다음과 같은 메모리 구조를 가진다.
+-------------------+
| Code | ← 실행 코드
+-------------------+
| Data | ← 전역 변수
+-------------------+
| Heap | ← 동적 메모리
+-------------------+
| Stack | ← 함수 호출 정보
+-------------------+
Code — 프로그램의 실행 코드가 저장되는 영역
Data — 전역 변수나 static 변수처럼 프로그램이 실행되는 동안 유지되는 값들
Heap — 동적으로 생성되는 객체들이 저장되는 영역 (예: new User())
Stack — 함수 호출과 관련된 정보 (지역 변수, 매개 변수, return address)
같은 프로세스 안에 있는 스레드들은
일부 메모리를 같이 사용하고 일부는 따로 사용한다.
같이 사용하는 영역
따로 사용하는 영역
Process
┌────────────────────────┐
│ Code │
│ Data │
│ Heap │
└────────────────────────┘
│ │
┌─────────┐ ┌─────────┐
│Thread 1 │ │Thread 2 │
│ Stack │ │ Stack │
└─────────┘ └─────────┘
즉 같은 프로세스 안의 스레드들은
공통된 자원은 함께 사용하면서도
실행 흐름 자체는 Stack으로 분리해서 관리한다.
Stack에는 실행 흐름에 필요한 정보가 들어간다.
예를 들어 이런 코드가 있다면
function A() {
int x = 10
B()
}
function B() {
int y = 20
}
Stack에는 이런 식으로 쌓인다.
B() ← y = 20
A() ← x = 10
만약 여러 스레드가 하나의 Stack을 같이 쓴다면
각자의 함수 호출 정보와 지역 변수, 복귀 위치가 서로 섞이게 된다.
그래서 스레드는
독립적인 실행 흐름을 유지하기 위해 Stack을 각각 따로 가진다.
CPU 코어는 동시에 처리할 수 있는 작업 수에 한계가 있다.
그런데 실제 시스템 안에는 그보다 훨씬 많은 스레드가 존재한다.
이때 운영체제는 스케줄링을 통해 스레드들을 아주 빠르게 번갈아 실행한다.
Time →
Thread A
Thread B
Thread C
Thread A
Thread B
전환 속도가 매우 빠르기 때문에
사용자 입장에서는 마치 동시에 실행되는 것처럼 보이게 된다.
Context Switch는
CPU가 지금 실행 중인 작업을 멈추고 다른 작업으로 바꾸는 과정이다.
여기서 Context는 현재 실행 상태를 다시 이어가기 위해 필요한 정보다.
흐름으로 보면
Thread A 실행
→ 현재 상태 저장
→ Thread B 실행
→ 현재 상태 저장
→ Thread A 다시 실행
CPU는 상태를 저장하고 복원하면서 여러 작업을 번갈아 처리한다.
프로세스는 서로 다른 메모리 공간을 가진다.
Process A Heap ≠ Process B Heap
그래서 서로 다른 프로세스 사이에서 데이터를 주고받아야 할 때는
운영체제가 제공하는 통신 방법을 사용해야 한다.
이걸 IPC (Inter Process Communication) 이라고 한다.
대표적인 방식
같은 프로세스 안에서 Thread A → Thread B 처럼 전환되는 경우.
Code, Data, Heap은 이미 공유하고 있으므로
Stack과 CPU 상태 위주로만 바뀐다. 비교적 가볍다.
Process A → Process B 처럼 아예 다른 프로세스로 바뀌는 경우.
같은 작업이 추가로 필요하다. 더 무겁다.
프로세스
스레드
IPC
Context Switch