Lecture 4. Threads & Concurrency
들어가며
Thread를 공부하면서 단순히 "프로세스보다 가볍다"는 말을 외우기보다, 왜 Thread가 등장했는지, 프로세스와 무엇이 같고 무엇이 다른지를 이해하는 데 집중했다. 이 글은 그 과정을 정리한 기록이다.
1. Thread가 왜 필요한가?
웹 서버로 이해하는 문제 상황
웹 서버는 동시에 수많은 클라이언트의 요청을 처리해야 한다. 클라이언트가 http://www.naver.com/index.html을 요청하면, 서버는 네트워크에서 요청을 받아 CPU로 처리하고 디스크에서 파일을 읽어 응답한다.
문제는 이 과정에서 디스크 I/O가 발생한다는 것이다. I/O 작업 중에는 서버가 blocked 상태가 되어 다른 클라이언트의 요청을 처리할 수 없다.
프로세스를 여러 개 만들면 안 되나?
직관적인 해결책은 클라이언트마다 서버 프로세스를 하나씩 fork()하는 것이다. 하지만 이 방법에는 두 가지 문제가 있다.
첫 번째는 메모리 낭비다. 모든 서버 프로세스는 동일한 코드를 실행하지만 fork()는 Code, Data, Stack, Heap을 모두 복사하므로 N개의 프로세스를 만들면 거의 동일한 메모리가 N벌 존재하게 된다.
두 번째는 생성 시간이다. 프로세스 생성은 메모리 복사와 PCB 초기화 등 상당한 비용이 든다.
Thread가 해결하는 방법
Thread는 프로세스 안에서 실행 흐름만 독립적으로 분리한 것이다. 같은 프로세스 안의 여러 스레드는 Code, Data, Heap을 공유하면서, Stack과 Registers와 Thread ID만 독립적으로 가진다. 서버 프로세스 하나에 N개의 스레드를 만들면, 코드와 데이터는 공유하므로 메모리를 N벌 복사할 필요가 없다.
2. Thread의 정의와 구조
Thread는 CPU 활용의 기본 단위(a basic unit of CPU utilization) 다. 각 프로세스는 하나 이상의 스레드를 포함할 수 있다.
같은 프로세스의 스레드들이 공유하는 것은 Code, Data, Heap, Open files, Signal handlers, Working environment(현재 디렉토리, user ID 등)다. 각 스레드가 독립적으로 갖는 것은 Stack, Registers, Thread ID다.
Stack이 독립적인 이유는 각 스레드가 서로 다른 실행 흐름을 가지기 때문이다. 함수 호출 순서와 지역 변수는 스레드마다 달라야 하므로 Stack은 공유할 수 없다. Registers가 독립적인 이유는 각 스레드가 CPU를 받았을 때 자신이 어디까지 실행했는지(Program Counter 포함)를 저장해야 하기 때문이다.

3. Thread vs Process
Thread 생성 방식 비교
fork()는 메모리 전체를 복사하지만, pthread_create()는 Stack만 새로 할당하고 나머지는 기존 프로세스와 공유한다. 그래서 Thread를 Lightweight Process(경량 프로세스) 라고 부르기도 한다.

Thread를 사용하는 네 가지 이점
- Responsiveness(응답성) 는 하나의 스레드가 I/O로 blocked되어도 다른 스레드는 계속 실행된다는 점이다.
- Resource Sharing(자원 공유) 은 같은 프로세스 내의 스레드들이 메모리와 자원을 자동으로 공유한다는 점이다. 단, 이것이 Race Condition의 원인이 되기도 한다.
- Economy(경제성) 는 프로세스 생성과 Context Switch의 오버헤드가 스레드보다 훨씬 크다는 점이다. 스레드는 Stack만 새로 할당하면 되므로 생성 비용이 낮다.
- Utilization of MP Architectures(멀티프로세서 활용) 는 멀티코어 CPU에서 여러 스레드를 각 코어에 분산하면 진정한 병렬 처리가 가능하다는 점이다.
프로세스와 스레드의 트레이드오프
| 특징 | 프로세스 | 스레드 |
|---|---|---|
| 메모리 격리 | 완전 격리 | 메모리 공유 |
| 안정성 | 한 프로세스 죽어도 OK | 하나 죽으면 전체 영향 |
| 생성 비용 | 높음 | 낮음 |
| Context Switch | 비쌈 | 저렴함 |
| 통신 방식 | IPC 필요 | 메모리 직접 공유 |
| Race Condition | 없음 | 발생 가능 |
4. Concurrency vs Parallelism
멀티코어 프로그래밍을 이해하려면 이 두 개념을 구분해야 한다.
- Concurrency(동시성) 는 여러 작업이 진행 중인 상태를 말한다. 싱글 코어에서도 스케줄러가 빠르게 Context Switch를 하면 여러 스레드가 동시에 진행되는 것처럼 보인다.
- Parallelism(병렬성) 은 여러 작업이 물리적으로 동시에 실행되는 것이다. 멀티코어 시스템에서만 가능하다.
싱글 코어는 한 순간에 하나의 스레드만 실행하지만 빠르게 교체하여 동시에 진행되는 것처럼 보인다. 멀티 코어는 여러 스레드가 각 코어에서 물리적으로 동시에 실행된다.
멀티코어 프로그래밍의 어려움
멀티코어 환경에서 스레드를 효율적으로 사용하려면 Dividing activities(작업을 독립 단위로 분리), Balance(코어에 균등 분배), Data splitting(데이터 분할), Data dependency(작업 순서 보장), Testing and debugging(비결정적 실행 순서로 재현 어려움) 등의 문제를 해결해야 한다.

5. User Threads vs Kernel Threads
스레드는 누가 관리하느냐에 따라 두 종류로 나뉜다.
- User Thread 는 사용자 수준 라이브러리가 관리하는 스레드다. OS 커널은 이 스레드의 존재를 모른다. POSIX pthreads, Win32 threads, Java threads가 대표적이다. 커널을 거치지 않으므로 생성과 Context Switch가 빠르다. 하지만 한 스레드가 System Call(I/O 등)로 blocking되면 커널은 프로세스 전체를 block시키기 때문에 다른 스레드들도 모두 멈춘다.
- Kernel Thread 는 운영체제가 직접 관리하는 스레드다. Windows, Linux, Mac OS X 등 현대 OS 대부분이 지원한다. 커널이 각 스레드를 독립적으로 스케줄링한다. 한 스레드가 blocking되어도 다른 스레드는 계속 실행된다. 대신 스레드 생성과 Context Switch에 System Call이 필요하므로 User Thread보다 비용이 더 든다.

6. Linux Threads
Linux는 스레드와 프로세스를 별도로 구분하지 않는다. 대신 clone() 시스템 콜로 "얼마나 공유할지"를 플래그로 지정해서 생성하며, 공유 범위에 따라 프로세스에 가까워지기도, 스레드에 가까워지기도 한다.
플래그를 많이 설정할수록 스레드에 가깝고, 적게 설정할수록 프로세스에 가깝다. clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, 0)은 스레드에 가깝고, clone(CLONE_SIGHAND, 0)은 프로세스에 가깝다. 스레드에 가깝게 clone()하면 두 task_struct가 mm(메모리), sighand(시그널 핸들러), fs(파일 시스템), files(열린 파일)를 모두 가리키는 포인터를 공유하게 된다.
즉, fork()와 clone(thread)의 차이는 자식이 부모의 자원을 복사하느냐, 공유하느냐의 차이다.

전체 정리
Thread는 CPU 활용의 기본 단위로, 프로세스 안에서 Code·Data·Heap을 공유하며 Stack·Registers·Thread ID만 독립적으로 가진다. 이 공유 덕분에 생성 비용이 낮고 통신이 쉽지만, Race Condition의 원인이 되기도 한다.
Concurrency는 싱글 코어에서 빠른 Context Switch로 동시 진행처럼 보이는 것이고, Parallelism은 멀티코어에서 물리적으로 동시 실행되는 것이다. User Thread는 빠르지만 blocking 문제가 있고, Kernel Thread는 안전하지만 비용이 높다. Linux는 clone() 플래그로 공유 범위를 조절하여 이 둘을 하나의 메커니즘으로 통합한다.
'Computer Science > OS(운영 체제)' 카테고리의 다른 글
| [OS] 3. 프로세스(Process)란? (0) | 2026.04.29 |
|---|---|
| [OS] 2. Operating System Structures (0) | 2026.04.29 |
| [OS] 1. Introduction to Operating Systems (0) | 2026.04.29 |
경이로운 BE 개발자가 되기 위한 프로그래밍 공부 기록장
도움이 되었다면 "❤️" 또는 "👍🏻" 해주세요! 문의는 아래 이메일로 보내주세요.