1. 프로그램과 프로세스
- 보조기억장치 : 프로그램이 저장된 곳
- 주기억장치 : 프로그램이 로딩되는 곳
- 프로세스 : 프로그램을 실행해주는 주체
- 자신만의 독립된 메모리 공간과 자원을 할당받아 사용함 (code, data, heap, stack)
- 최소 한 개의 쓰레드를 보유하고 있음
- 쓰레드 : 프로세스 안에서 작업을 처리해주는 주체
- 자원 중 stack만 할당받고, 나머지는 다른 쓰레드와 공간과 자원을 공유하면서 사용함
2. 프로세스 생명주기
2-1. 프로세스 상태 (status)
- 신규 (New) : 프로세스가 메인 메모리에 막 올라온 상태
- 수용(admit) 동작을 거쳐야 "준비" 단계로 넘어감
- 준비 (Ready) : 변수 초기화 작업 등 기초 작업을 마치고 실행을 할 수 있는 상태
- 스케줄러를 통해 발송(scheduler dispatch)을 통해 "수행" 단계로 넘어감
- 수행 (Running) : CPU가 실제로 프로세스를 수행하고 있는 상태
- 선점 스케줄리에 의해 중단되면 "준비" 상태로 넘어감
- 입출력 또는 이벤트가 필요하면 "대기" 상태로 넘어감
- 수행이 완료되면 "종료" 상태가 됨
- 대기 (Waiting) : 프로세스 도중 입출력(I/O) 작업 또는 이벤트가 필요해, 해당 작업을 수행하는 상태
- 대기 상태가 끝나면 다시 "준비" 상태로 넘어감
- 종료 (Terminated) : 최종적으로 프로세스가 종료된 상태
2-2. 대기 큐 (Waiting Queue)
- Job Queue : 보조기억장치(HDD)에 있던 프로그램들이 메모리에 올라올 때 거치는 곳
- Ready Queue : 메인 메모리에 올라온 프로그램이 CPU에 의해 실행되기 전에 대기하는 곳
- Device Queue : 입출력장치를 이용해야 할 때 기존 입출력 작업이 있다면 기다리는 곳 (예: 프린터 큐)
2-3. 문맥 교환 (Context Switching)
-
실행하는 프로세스를 바꾸는(switching) 것
CPU 시간공유 시스템에서 일정 시간이 지나면, 기존 프로세스를 준비 상태로 만들고 다른 프로세스를 수행 상태로 만들어 실행하는 것
-
Dispatcher : 수행 중이던 프로세스가 다시 준비 상태로 스위치될 때, 기존에 수행 중이던 정보를 저장하는 작업을 수행하는 프로그램
3. 프로세스 메모리
3-1. 프로세스의 메모리 구조
- Code 영역 : 실행할 프로그램의 코드가 저장됨
- Data 영역 : 전역 변수와 정적 변수가 저장됨
- Stack 영역 : 호출된 함수의 수행을 마치고 복귀할 주소 및 데이터(지역변수, 매개변수, 리턴값)가 임시로 저장됨
- Heap 영역 : 동적 데이터 영역
- 메모리 주소 값에 의해서만 참조되고 사용됨
- 프로그램 동작 시, 런타임에 의해 크기가 결정됨
3-2. 커널 프로세스의 메모리
커널(Kernel) : 운영 체제(OS)의 주요 구성 요소이며 컴퓨터 하드웨어와 프로세스를 잇는 핵심 인터페이스
- Code, Data, Stack 영역이 있음
- Data 영역에는 PCB가 저장됨
- PCB(Process Control Block) : 프로세스의 실행 정보와 상태 정보를 저장하는 자료구조
- Heap 메모리는 사용하지 않음
4. 쓰레드
4-1. 프로세스 vs 쓰레드
- 프로세스 : 프로그램을 실행해주는 주체
- 자신만의 독립된 메모리 공간과 자원을 할당받아 사용함 (code, data, heap, stack)
- 최소 한 개의 쓰레드를 보유하고 있음
- 쓰레드 : 프로세스 안에서 작업을 처리해주는 주체
- 자원 중 stack만 할당받고, 나머지는 다른 쓰레드와 공간과 자원을 공유하면서 사용함
4-2. 멀티 프로세스 vs 멀티 쓰레드
- 멀티 프로세스 : 하나의 운영체제 안에서 여러 프로세스가 실행됨
- 하나의 프로세스가 다른 프로세스에 영향을 미치지 않음
- 각각 독립된 메모리 영역을 갖고 있어, 오버헤드 발생 및 Context Switching 으로 인한 성능 저하
- IPC 등을 이용한 프로세스 사이의 통신이 복잡함
- 멀티 쓰레드 : 하나의 프로세스가 여러 쓰레드를 사용해 여러 작업을 동시에 처리함
- 프로세스 생성을 위한 시스템 콜이 줄어 자원을 효율적으로 관리 가능
- 공유 자원이 있어, 데이터 교환이 간단하고 자원 소모가 적음
- 쓰레드 사이의 작업량이 작아 Context Switching이 빠르고, 시스템 처리량 증가
- 에러를 추적하기 어려움 (디버깅 힘듦)
- 하나의 쓰레드에 문제가 생기면 전체 프로세스에 영향
- 공통된 전역 변수를 사용하는 동기화 문제
5. 쓰레드 풀
쓰레드 풀 : 작업 처리에 사용되는 쓰레드의 개수를 정해두고, 작업 큐에 들어온 작업들을 쓰레드가 하나씩 맡아서 처리하는 것
쓰레드 풀을 사용하는 이유
1. 프로그램 성능 저하 방지 (쓰레드 생성/수거에 따른 부담이 사라짐)
2. 다수의 사용자 요청 처리
- 장점 : 쓰레드 생성/수거 비용이 들지 않음
- 단점 : 처음에 쓰레드를 많이 생성해두고 사용하지 않으면 메모리 낭비 발생
멀티 코어와 싱글 코어에서의 쓰레드 풀
- 동시성 : 싱글 코어에서 멀티 쓰레드를 동작시킬 때 사용되는 방식
- 병렬적으로 실행되는 것처럼 보여도, 실제로는 빠른 속도로 번갈아가면서 조금씩 실행하는 것
- 병렬성 : 멀티 코어에서 멀티 쓰레드를 동작시킬 때 사용되는 방식
- 한 개 이상의 쓰레드를 포함하는 각 코어들이 동시에 실행됨
- 데이터 병렬성 : 전체 데이터를 멀티 코어 수만큼의 서브 데이터로 쪼갠 후, 병렬 처리하여 빠르게 수행함
- 작업 병렬성 : 서로 다른 작업을 병렬 처리함