프로세스와 스레드의 차이점과 컨텍스트 스위칭
프로세스(Process)와 스레드(Thread) 개념
프로세스(Process)
프로세스는 실행 중인 프로그램의 인스턴스로, 운영체제로부터 시스템 자원을 할당받아 독립적으로 실행되는 작업 단위입니다.
주요 특징:
- 독립된 메모리 공간 소유 (Code, Data, Heap, Stack)
- 다른 프로세스와 완전히 격리됨
- 프로세스 간 통신을 위해서는 IPC(Inter-Process Communication) 필요
- 생성과 종료에 많은 오버헤드 발생
스레드(Thread)
스레드는 프로세스 내에서 실행되는 실행 흐름의 단위로, 프로세스의 자원을 공유하면서 독립적으로 실행됩니다.
주요 특징:
- 같은 프로세스 내의 스레드들은 메모리 공간 공유 (Code, Data, Heap 영역)
- 각 스레드는 독립적인 Stack과 PC(Program Counter) 보유
- 스레드 간 데이터 공유가 쉬움
- 생성과 전환에 상대적으로 적은 오버헤드
메모리 구조 비교
프로세스 메모리 구조
프로세스 A 프로세스 B
┌──────────┐ ┌──────────┐
│ Stack │ │ Stack │
├──────────┤ ├──────────┤
│ Heap │ │ Heap │
├──────────┤ ├──────────┤
│ Data │ │ Data │
├──────────┤ ├──────────┤
│ Code │ │ Code │
└──────────┘ └──────────┘
독립적 독립적
스레드 메모리 구조
하나의 프로세스
┌─────────────────────────────┐
│ Thread1 Thread2 Thread3 │
│ Stack Stack Stack │
├─────────────────────────────┤
│ 공유 Heap │
├─────────────────────────────┤
│ 공유 Data │
├─────────────────────────────┤
│ 공유 Code │
└─────────────────────────────┘
컨텍스트 스위칭(Context Switching)
컨텍스트 스위칭은 CPU가 한 작업에서 다른 작업으로 전환할 때 발생하는 과정입니다.
프로세스 컨텍스트 스위칭
과정:
- 현재 실행 중인 프로세스의 상태를 PCB(Process Control Block)에 저장
- 새로 실행할 프로세스의 PCB에서 상태 정보를 로드
- 메모리 맵, 페이지 테이블 전환
- 캐시 플러시 (Cache Flush) 발생
저장되는 정보:
- CPU 레지스터 값들
- 프로그램 카운터(PC)
- 스택 포인터
- 메모리 관리 정보 (페이지 테이블 등)
- 프로세스 상태 정보
오버헤드가 큰 이유:
- 메모리 맵 전환으로 인한 TLB(Translation Lookaside Buffer) 플러시
- CPU 캐시 무효화
- 페이지 테이블 전환
스레드 컨텍스트 스위칭
과정:
- 현재 스레드의 레지스터 상태를 TCB(Thread Control Block)에 저장
- 새로운 스레드의 레지스터 상태를 로드
- 스택 포인터 전환
저장되는 정보:
- CPU 레지스터 값들
- 프로그램 카운터(PC)
- 스택 포인터
- 스레드별 로컬 데이터
오버헤드가 적은 이유:
- 메모리 맵 전환 불필요 (같은 프로세스 내)
- 캐시 플러시가 발생하지 않음
- 페이지 테이블 공유
성능과 오버헤드 비교
생성/종료 비용
- 프로세스: 높음 (메모리 할당, 페이지 테이블 생성 등)
- 스레드: 낮음 (스택 영역만 추가 할당)
컨텍스트 스위칭 비용
- 프로세스: 높음 (수십 마이크로초)
- 스레드: 낮음 (수 마이크로초)
메모리 사용량
- 프로세스: 높음 (독립적인 메모리 공간)
- 스레드: 낮음 (메모리 공간 공유)
동기화와 통신
프로세스 간 통신 (IPC)
프로세스는 독립적인 메모리 공간으로 인해 특별한 통신 방법이 필요합니다.
IPC 방법들:
- 파이프(Pipe): 부모-자식 프로세스 간 통신
- 공유 메모리(Shared Memory): 메모리 영역을 공유하여 통신
- 메시지 큐(Message Queue): 메시지 기반 통신
- 소켓(Socket): 네트워크를 통한 통신
스레드 간 통신
스레드는 메모리를 공유하므로 통신이 간단하지만, 동기화 문제가 발생할 수 있습니다.
동기화 방법들:
- 뮤텍스(Mutex): 상호 배제를 위한 락
- 세마포어(Semaphore): 리소스 접근 제한
- 조건 변수(Condition Variable): 특정 조건 대기
- 스핀락(Spinlock): 바쁜 대기 방식의 락
언제 무엇을 사용할까?
프로세스를 사용하는 경우
- 안정성이 중요한 경우: 한 프로세스 오류가 다른 프로세스에 영향을 주지 않음
- 보안이 중요한 경우: 프로세스 간 완전한 격리
- 독립적인 작업: 서로 다른 애플리케이션 실행
- 예시: 웹 브라우저 탭, 멀티프로세싱 웹 서버
스레드를 사용하는 경우
- 성능이 중요한 경우: 빠른 생성/전환, 적은 메모리 사용
- 데이터 공유가 필요한 경우: 같은 데이터를 여러 작업에서 처리
- 응답성이 중요한 경우: UI 프로그램에서 백그라운드 작업
- 예시: 웹 서버의 요청 처리, 게임의 렌더링과 로직 분리
실제 시스템에서의 활용
웹 서버 아키텍처
- Apache 전통 모델: 프로세스 기반 (안정성 우선)
- Nginx: 이벤트 기반 + 적은 수의 워커 프로세스
- Node.js: 단일 스레드 + 이벤트 루프
브라우저 아키텍처
- Chrome: 프로세스 격리 (탭마다 별도 프로세스)
- 렌더링: 메인 스레드 + 워커 스레드 조합
참고 자료
- HTTP-HTTPS-SSL-TLS-OSI-네트워크-기초 - 네트워크 프로토콜 이해
- JWT와 세션 인증 방식 비교 - 웹 애플리케이션에서의 상태 관리
마무리
프로세스와 스레드는 각각 고유한 장단점을 가지고 있으며, 시스템의 요구사항에 따라 적절히 선택해야 합니다. 안정성과 격리가 중요하다면 프로세스를, 성능과 효율성이 중요하다면 스레드를 고려해보세요. 현대의 많은 시스템들은 두 방식을 적절히 조합하여 사용하고 있습니다.