[Operating System] 프로세스 (Process)
프로세스의 정의
프로세스란, 실행 중인 프로그램 (a program in execution) 을 의미합니다. 실행 중 (in execution) 의 의미는 뒤에서 다룰 내용인 프로세스의 Running 상태와는 다른의미입니다. 프로그램은 인스트럭션의 연속이었음을 떠올리며 공부해봅시다.
프로세스는 누구에 의해 생성되는가?
프로세스는 무엇에 의해 생성될 수 있을까요?
1. By a human
사람이 GUI 나 Command Line Interface 와 같은 Command Interface 를 통해서 프로그램을 실행시킬 수 있습니다. 즉, 프로세스가 생성될 수 있습니다.
2. By a process
운영체제의 프로세스나 유저 프로세스에 의해서 프로세스가 생성될 수 있습니다.
프로세스는 누구에 의해 종료되는가?
프로세스는 어떤 이유로 종료될 수 있을까요?
1. Normal Completion : 프로세스가 프로그램에 주어진 인스트럭션을 모두 마치고 시스템 콜을 호출하여 OS 로 하여금 프로세스를 종료시키게 합니다.
2. Protection Error : 프로세스가 접근할 수 없는 메모리 주소로 접근하려 할 때 프로세스가 종료됩니다.
3. Parent Request : 부모 프로세스가 자식 프로세스를 종료시키도록 OS 에 요청할 수 있습니다.
4. Arithmetic Error, I/O Failure, Invalid Instruction, et cetera : Division By Zero 와 같이 복구 불가능한 Abort ECF 발생 시 프로세스가 종료될 수 있습니다.
프로세스의 구성요소
프로세스는 세가지 구성요소로 이루어져있습니다.
- An Executable Program (code or text)
- Data used in program
- Execution context of the program (실행 중인 프로세스의 한 순간의 상태를 담고 있는 context, 시스템 프로그래밍에서 배운 context switching 에 대해 떠올려봅시다.)
위 그림을 보면 프로세스 리스트가 각 프로세스의 context 의 메모리 주소를 가리키고 있습니다. 이 프로세스 리스트는 PCB 로 이루어져있는데 이에 대해서는 아래에서 다룹니다.
프로세스의 상태
이번에는 프로세스의 상태에 대해서 알아보도록 하겠습니다.
이전 포스팅에서 프로세서가 처리하는 프로세스는 스케쥴러에 의해서 변할 수 있다는 것을 알았습니다. (Time sharing, Multi-Programming) 이렇게 처리하는 프로세스를 바꾸는 것은 커널 안의 Dispatcher 라는 function 이 수행합니다.
다음은 Time Sharing 방식의 프로세스 관리 방식에서 Dispatcher 의 동작 형태를 살펴본 그림입니다.
위 그림에서 Time out 시 메모리 100번지에 위치하는 Dispatcher Funtion 이 호출되어 프로세서가 처리 중인 프로세스가 바뀌게 됩니다.
저는 처음에 왜 Time out 이 Interrupt 고 I/O Request 가 System call (Trap) 인지 의문이 들었습니다. 오히려 타임아웃이 시스템 콜, I/O Request 가 인터럽트여야 맞다고 생각했는데 위 상황에서는 I/O Request 가 프로그램의 정상적인 제어흐름의 일부이고 Time out 은 프로그램은 인지할 수 없는 Asynchronous Event 이므로 인터럽트로 이해하는 것이 맞는 것 같습니다.
위처럼, 메모리에는 여러 프로세스 (a program in execution) 이 존재할 수 있고 이 프로세스는 Running 상태 (프로세서를 할당받아 인스트럭션을 처리하고 있는 상태) 일 수도 있고, 아닐 수도 있습니다.
따라서 프로세스의 상태는 크게 다섯가지로 나뉩니다. (Five-State Model)
- New
- Running
- Not-Running
- Ready
- Blocked
- Terminated
New 는 프로그램을 실행시키는 Command 에 의해서 프로세스가 생성된 상태입니다. 이것은 Not-Running 상태에 있다가 프로세서를 할당받으면 Running 상태가 되는 것입니다.
Not-Running 상태는 Ready 상태와 Blocked 상태로 나뉠 수 있습니다. Not-Running 상태의 프로세스가 프로세서를 할당받았을 때 인스트럭션을 수행할 수 있는 상태면 Ready 상태입니다. 그러나, I/O Request 와 같은 동작이 처리되기 전까지 프로세서를 할당받아도 프로세스의 인스트럭션을 수행할 수 없는 상태를 Blocked 상태라고 합니다.
이 모든 State 를 그림으로 나타내면 다음과 같습니다.
다음은 한 프로세서가 프로세스 A, B, C 를 처리할 때 각 프로세스의 State 를 나타낸 그림입니다.
아까 프로세스의 상태는 "크게" 다섯가지로 나뉜다고 했습니다. 그 말은 즉 더 세세하게 분류가 가능하다는 이야기입니다.
앞서 말한 다섯가지 상태 외에도 두가지 상태가 더 존재합니다. 이 두가지 상태는 Not-Running (Ready, Blocked) 의 상태를 세분화합니다.
- Ready/Suspend (Suspended Ready)
- Blocked/Suspend (Suspended Block)
Suspend 상태란 User Context of a process is moved from main memory to hard disk 를 의미합니다. 즉 프로세스가 메인 메모리에 있지 않고 보조기억 장치에 있는 상태입니다.
어째서 프로세스가 보조 기억장치로 내려가는 일이 발생할까요? 결론부터 말하면 메인 메모리 Utilization 을 극대화시키기 위해서입니다.
일반적으로, 프로세서는 I/O Device 보다 빠르게 동작합니다. 즉 프로세스가 I/O Request 를 처리하고 있다면 이 프로세스는 프로세서를 할당받아도 인스트럭션을 수행하지 못할 확률이 큽니다. 이런 프로세스가 메인 메모리에서 많은 자원을 차지하고 있다면, 이는 자원 낭비입니다.
또는 아주 주기적으로 실행되는 프로그램의 경우, 이를 메인 메모리에 프로세스로 만들어 상주시킬 필요가 없습니다. 필요할 때만 잠시 메인 메모리로 가져와 실행시키고 메인 메모리에서 비워버려 자원을 효율적으로 사용하는 것이 중요합니다.
이렇게 메인 메모리에서 보조기억 장치로 혹은 그 반대의 방향으로 프로세스를 옮기는 것을 Swap 이라고합니다.
다음 그림은 Five State Process Model + Suspend State 를 나타낸 그림입니다.
프로세스 상태 별 메모리 상의 모습
위 그림에서 볼 수 있듯, Running 상태의 프로세스는 프로세서에서 처리되고 있고, Not-Running 상태 중 Ready 상태의 프로세스는 Ready Queue 에서 대기하고 있다가 Dispatcher Function 에 의해서 프로세서로 들어갑니다.
그리고 Blocked 상태의 프로세스는 어떤 이유로 Block 이 되었는지에 따라 별도의 Queue 로 관리됩니다. (I/O Request ...)
정지되었던 프로세스는 어떻게 다시 Running 상태로 돌아갈 수 있을까?
위 질문에 대한 해답은 PCB (Process Control Block) 에 있습니다.
OS 는 프로세스들을 관리하기 위해 Process Description 이라는 Data Structure Table 을 가지고 있습니다. Process Description 은 프로세스와 resource 의 current state 에 대한 정보를 담고 있습니다.
이 Process Description 의 구체적 예시가 PCB 입니다. 하나의 프로세스는 그에 대응하는 하나의 PCB 를 갖습니다.
PCB 의 구조는 아래 그림과 같습니다.
리눅스의 PCB 인 Process Descriptor 의 경우 Struct 안에 Struct 를 가지고 있습니다. (여기서 struct 는 c언어의 구조체)
아까 프로세스에 관한 설명을 할 때 아래 그림에 프로세스 리스트가 있던 것을 기억하시나요?
이 프로세스 리스트의 실상이 Double Linked List 로 연결된 PCB 들입니다. 위 그림에서는 연속된 메모리 주소에 위치한 것처럼 보이지만 Double Linked List 로 구현되어 있으므로 실제로는 연속된 메모리 주소상에 위치할 필요도 없습니다.
이 프로세스 리스트는 프로세스 state 별로 존재합니다. 즉 run_queue 는 running 상태의 프로세스 리스트이고, blocked 상태는 그들만의 프로세스 리스트 들이 존재합니다. 아래 그림을 다시 보면 이해가 한층 깊어질 것입니다.
PCB 의 구조를 살펴보면 PCB 는 자신을 식별할 수 있는 Identifier 와 함께 프로세스의 어느 한 시점의 current state 의 정보 (다음 인스트럭션의 주소를 가리키는 Program Counter 의 값, 그 외 필요한 Data 들)를 담고 있습니다. 만약 Running 하다가 어떤 이유로 (Time out, I/O Request ...) Not-Running 이 된 프로세스가 있다면 이 PCB 를 이용해서 다시 Running 상태로 돌아갈 수 있는 것입니다.
아래 그림은 Context Switching 이 일어나는 모습입니다.
다음은 PCB 가 가질 수 있는 구조의 한 형태와 설명입니다.