| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 |
- html
- 혼자 공부해서 개발까지
- 코딩
- BFS
- js
- 정글
- Git
- 프로그래머스
- Mini-React
- 개발자
- DFS
- 백준
- CSS
- 프론트엔드
- 프론트앤드
- 그리디
- 팀프로젝트
- 알고리즘 기초
- react
- HTML기초
- 해시
- c언어
- 정렬
- 코딩테스트
- 크래프톤 정글
- 알고리즘
- 그래프
- javascript
- Python
- frontend
- Today
- Total
민혁이의 IT스토리
[Pintos - threads] - 구현 전 개념 정리 본문
프로세스와 스레드의 관계
프로세스(Process) 는 실행 중인 프로그램의 인스턴스로,
각자 독립된 메모리 공간(Code, Data, Stack, Heap)을 갖는다.
하지만 프로세스 간 전환은 느리고, 자원 공유가 어렵다.
스레드(Thread) 는 한 프로세스 내부에서 실행 흐름을 여러 개로 나눈 것이다.
스레드들은 같은 메모리 공간(코드, 데이터, 힙) 을 공유하지만
자신만의 스택(Stack) 과 레지스터(실행 상태) 를 가진다.
👉 즉, 스레드는 “프로세스의 실행 단위” 이며,
하나의 프로그램이 동시에 여러 일을 처리할 수 있게 한다.
스레드의 필요성
1. 성능
스레드는 메모리 공유 덕분에 프로세스보다 전환이 빠르다.
새 스레드를 만드는 비용은 프로세스를 만드는 것보다 훨씬 작다.
2. 병렬성 (Parallelism)
멀티코어 CPU에서는 여러 스레드를 동시에 실행할 수 있다.
예: 웹 브라우저
- 렌더링 스레드
- 사용자 입력 처리 스레드
- 네트워크 요청 스레드
3. 자원 효율성
같은 주소 공간을 공유하므로,
데이터를 복사하지 않고도 스레드 간에 손쉽게 통신 가능하다.
스레드 구성요소
스레드는 단순히 “코드가 동시에 실행되는 흐름”이 아니라,
운영체제가 그 흐름을 추적하고 제어하기 위해 관리하는 하나의 독립된 실행 단위예요.
그 내부에는 다음과 같은 핵심 구성 요소들이 있습니다
1. 스택(Stack)
스택은 함수 호출과 지역 변수를 저장하는 공간이에요.
스레드가 실행될 때, 함수가 호출될 때마다 스택 프레임이 쌓이고,
함수가 끝나면 프레임이 사라지죠 (LIFO, 후입선출 구조).
- 각 스레드는 자신만의 스택을 가진다.
→ 다른 스레드의 스택에는 절대 접근하지 않는다 - 스택에는 함수의 매개변수, 지역 변수, 리턴 주소 등이 저장된다.
- 스택이 너무 커지면 ‘스택 오버플로(Stack Overflow)’가 발생한다.
2. 레지스터(Registers)
레지스터는 CPU 내부의 초고속 저장소로,
스레드가 지금 “무엇을 계산 중인지”를 담고 있다.
특히 중요한 레지스터는 다음과 같다.
- Program Counter (PC): 지금 실행 중인 명령의 주소
- Stack Pointer (SP): 스택의 현재 꼭대기 위치
- General Registers: 계산 중인 데이터, 중간 결과
운영체제는 스레드가 바뀔 때(context switch)
이 레지스터 값들을 저장했다가 다시 복원한다.
레지스터는 “CPU 안에서 스레드가 현재 어떤 일을 하고 있는지”를 나타내는 실행 상태예요.
3.스레드 ID(Thread ID)
스레드 ID는 스레드를 구별하기 위한 고유 식별자예요.
운영체제가 여러 스레드를 동시에 관리하려면
각 스레드를 식별할 수 있어야 하죠.
- 프로세스 안의 모든 스레드는 서로 다른 ID를 가집니다.
- 이 ID는 스케줄러가 “누구 차례인지” 판단할 때도 사용됩니다.
- 대부분의 OS에서 pthread_self() 또는 GetCurrentThreadId() 같은 함수로 확인 가능합니다.
4. 상태(State)
스레드는 실행 중 항상 특정한 상태(state) 에 있습니다.
이 상태는 운영체제가 스레드 스케줄링을 관리하는 핵심 기준입니다.
스레드의 생명주기 (Thread Lifecycle)
NEW → READY → RUNNING → BLOCKED → TERMINATED
| 상태 | 설명 |
| NEW | 생성되었지만 아직 실행되지 않음 |
| READY | CPU 할당을 기다리는 상태 |
| RUNNING | CPU를 점유해 실제로 실행중 |
| BLOCKED | 입출력 대기나 락(LOCK) 획득 등으로 멈춰 있음 |
| TERMINATED | 실행이 완료되어 종료된 상태 |
문맥 교환 (Context Switch)
CPU는 한 번에 하나의 스레드만 실행할 수 있다.
따라서 여러 스레드를 동시에 실행하려면
아주 빠른 속도로 스레드를 바꿔가며 실행해야 한다.
이때 필요한 과정이 바로 문맥 교환(Context Switch) 이다.
Context Switch란?
현재 스레드의 실행 정보를 저장하고, 다음 스레드의 정보를 복원하는 과정.
저장되는 정보: 레지스터, 스택 포인터, 프로그램 카운터 등
문맥 교환은 필연적으로 오버헤드가 있으므로
스레드 수가 너무 많아도 성능이 떨어질 수 있다.
스케줄링 (Scheduling)
운영체제는 어떤 스레드가 언제 실행될지를 결정해야 한다.
이를 스케줄링 정책(Scheduling Policy) 라고 한다.
| 정책 | 설명 |
| FIFO(First In First Out | 먼저 온 스레드부터 실행 |
| Round Robin | 각 스레드에 일정 시간(TIME SLICE)을 번갈아 할당 |
| Priority Scheduling | 우선운위(priority)가 높은 스레드부터 실행 |
| MLFQ(Multi-Level Feedback Queue) | CPU 사용 패턴에 따라 우선순위를 동적으로 조정 |
스케줄러의 목표는
- CPU 자원의 공평한 분배
- 응답성 향상 (interactive 시스템)
- 처리량 증가 (throughput)
- 기아(starvation) 방지
이다.
동기화(Synchronization)
여러 스레드가 동시에 같은 데이터를 접근하면 경쟁 상태(Race Condition) 가 발생한다.
-> 한 스레드가 수정 중인 데이터를 다른 스레드가 읽으면 잘못된 결과가 나올 수 있다.
이를 방지하기 위해 동기화(Synchronization) 메커니즘을 사용한다.
| 도구 | 설명 |
| Mutex (뮤텍스) | 한 번에 하나의 스레드만 critical section 진입 허용 |
| Semaphore (세마포어) | 접근 가능한 스레드의 개수를 제한 |
| Monitor / Condition Variable | 조건을 만족할 때만 스레드가 실행되도록 제어 |
스레드의 장단점
장점
- 빠른 생성 및 전환
- 데이터 공유가 용이
- 병렬 처리 가능
단점
- 동기화 문제 발생 가능
- 하나의 스레드 오류가 프로세스 전체에 영향
- 디버깅 어려움
'Pintos > Threads' 카테고리의 다른 글
| [Pintos - threads] - donation 개념 정리 (0) | 2025.12.05 |
|---|---|
| [Pintos - thread] - Alarm 구현 (0) | 2025.11.12 |