프로세스와 스레드 엄청 많이 들어보는 말이지만 막상 딥다이브를 경험해보다 보면 기본 지식이 부족하다는 것을 종종 느낄때가 있다. 결국 컴퓨터로 만드는 프로그램은 컴퓨터 과학(CS)을 기반으로 만들게 된다. 그렇기에 더욱 기본을 탄탄하게 다지는 것에 대해서 중요성을 느끼고 프로세스와 스레드에 대한 차이를 기반으로 멀티 프로세스 스레드 환경에서 어떻게 작동을 하며 여기서 공유하는 영역은 어디며 공유를 하면 어떠한 장단점이 있고 문제점을 보완하기 위해 어떠한 개념들이 적용되었는지에 대해서도 정리를 해보고자 한다.
우선, 해당 글에서는 프로세스와 PCB를 우선적으로 정리한다.
프로세스
프로세스는 컴퓨터 프로그램의 인스턴스라고 하며 프로그램을 실제로 CPU의 자원을 통해서 실행하는 것을 의미한다.
프로세스 구조
Stack : 지역 변수와 같은 호출한 함수가 종료되면 돌아올 임시적인 자료를 저장하는 독립적인 공간이다. Stack은 함수의 호출과 함께 할당되며, 함수의 호출이 완료되면 Stack은 사라진다. 만약, Stack영역을 초과하면 발생하는 에러가 Stack Overflow이다.
Heap : 동적으로 할당되는 데이터(생성자 인스턴스 등)들을 위해 존재하는 공간으로 사용자에 의해 메모리 공간이 동적으로 할당되고 해제되는 공간이다.
Data : 코드가 실행되면서 생성되는 전역 변수나 각종 데이터들이 모여있는 공간으로 데이터 영역은 data, BSS, rodata로 더 세분화를 할 수 있다.
text : Code 영역이라고도 불리며 프로그램 함수의 코드가 CPU가 해석 가능한 기계어 형태로 저장되는 공간이다.
프로세스 상태
프로세스는 커널 내에서 준비, 대기, 실행을 관리하는 큐가 있는데 이것들을 이용하여 커널은 프로세스의 상태를 관리한다.
(Ready을 Wait라고도 한다)
1. Created(생성) → Ready(준비)
CPU는 동시에 두가지 일을 할 수 없기에 스케줄러에 의해 호출이 되기를 기다리고 있는 상태가 Ready 상태이며 이를 Admitted라 한다.
2. Ready(준비) → Running(실행)
준비 큐에 맨 앞에 있던 프로세스가 CPU를 점유하고 실행하는 상태(Running)으로 변경하며 이를 바꾸는 것을 Dispatch라 한다.
3-1. Runnig(실행) → Ready(준비)
프로세스의 할당시간의 만료하는 경우 혹은 우선순위 알고리즘을 택하고 있는 시스템에서 높은 우선순위의 프로세스가 오는 경우에 스케줄러에 의해 Ready 상태에 돌입하는데 이를 Interrupt라 한다.
3-2. Runnig(실행) → Blocked(보류)
프로세스의 할당 시간을 만료하기 전에 입출력 동작을 필요로 하는 경우에는 시스템에서 높은 우선순위의 프로세스가 오는 경우 해당 상태에서 이벤트를 대기 조건을 기준으로 스케줄러에 의해 준비상태로 변경된다.
4. Blocked(보류) → Ready(준비)
3-2에서 이벤트 대기 조건을 만족하는 경우 다시 Ready 상태에 돌입한다.
5. Runnig(실행) → Terminated(종료)
프로세스의 실행을 완료하고 종료 되는 것을 의미한다. 하지만, 운영체제가 에러 발생을 감지하고 프로세스를 강제로 종료시키는 경우는 스케줄러에 의해 종료된다.
Process Control Block, PCB (프로세스 제어 블록)
프로세스의 관리를 위해 운영체제는 프로세스 제어블록을 통해 정보를 보관한다.
PCB 위치
PCB는 프로세스의 중요한 정보를 보관하고 있기 때문에, 일반 사용자가 접근하지 못하도록 보호된 메모리 영역 안에 들어가며 일부 운영체제에서는 PCB는 커널 스택의 처음에 위치한다. (이 메모리 영역은 편리하면서도 보호를 받는 위치이기 때문에 처음에 위치한다)
PCB 구조
Pointer : 프로세스의 현재 위치를 저장한다.
Process State : 프로세스의 상태에 대한 정보를 저장한다.
Process Number (PID) : 프로세스의 고유한 ID를 저장한다.
Program Counter : 프로세스가 실행해야 하는 다음 명령어 주소를 저장한다.
Registers : Accumulator(누산기), Base (베이스), 레지스터 및 범용 레지스터를 포함하는 CPU 레지스터에 있는 정보를 저장한다.
Memory Limits : OS에서 사용하는 메모리 관리 시스템에 대한 정보가 저장한다.
PS. 여기서 CPU는 한번에 두가지 일을 못하는데 여러 일을 번갈아 가면서 일을 하는데 PCB에 프로세스에 대한 정보를 저장하고 실행하고자 하는 PCB를 읽어 오는 과정을 Context Switching이라 한다. 해당 글에서는 컨텍스트 스위칭은 분량 조절로 다른 포스팅에서 설명한다.
Context Switching
컨텍스트 스위칭 과정
- P_0 실행 중
- P_0가 실행 상태에서 작동 중이다.
- 인터럽트 또는 시스템 호출 발생.
- 상태 저장 및 P_1로 전환
- 운영 체제가 P_0의 상태를 PCB_0에 저장.
- P_0는 idle 상태로 전환됨.
- PCB_1에서 P_1의 상태를 불러와 P_1가 실행 상태로 전환됨.
- PCB 실행 중
- P_1이 실행 상태에서 작동 중이다.
- 인터럽트 또는 시스템 호출 발생.
- 상태 저장 및 P_0로 재전환
- 운영 체제가 P_1의 상태를 PCB_1에 저장.
- P_1은 idle 상태로 전환됨.
- PCB_0에서 P_0의 상태를 불러와 P_0가 재실행됨.
Context Switching Overhead
위의 그림에서 컨텍스트 스위칭 과정에서 P_0이 실행되고 execute에서 idel이 될때 P2가 idle 상태에서 대기하다가 excute가 되는 것을 알 수 있다. 이점이 Context Switching Overhead인 것이다.
컨텍스트 스위칭 오버헤드는 아래와 같은 행위에서 발생한다.
- PCB 저장 및 복원 비용
- CPU 캐시 메모리 무효화에 따른 비용
- 프로세스 스케줄링 비용
이 오버헤드로 인해서 멀티 스레드가 싱글 스레드보다 성능이 떨어지는 현상이 나타날 수 있기 때문에 상황에 알맞게 사용하는 것이 가장 중요하다.
Reference.
https://www.cs.uic.edu/~jbell/CourseNotes/OperatingSystems/3_Processes.html