프로세스 스케쥴링
우리는 일반적으로 많은 프로그램을 동시에 사용하고 있다.
실행 중인 프로그램을 프로세스라고 하기에, 많은 프로세스가 동시에 동작하고 있다고 생각할 수 있겠다.
하지만, 가장 기본적인 cpu core 구성이라고 가정하였을 때 하나의 프로세스가 cpu를 점유하고 있으면 다른 프로세스는 이를 기다려야 한다.
그렇다면, 누가 먼저 실행되고 누가 나중에 실행되는가? 나중에 실행되는 프로세스는 이전 프로세스가 종료될 때 까지 계속 기다려야 하는가? 이런 의문점들이 생긴다.
또한, 우리는 cpu를 최대한 효율적으로 사용함과 동시에 위에 언급한 대로 하나의 프로그램이 아니라 여러 개의 프로그램과 동시에 상호작용을 하고 싶다. 유튜브 보면서 카카오톡도 하고, 게임도 해야할 것 아닌가? 이러한 상황에 직면하면, 우리는 프로세스를 스케쥴링 (Process Scheduling) 하는 것이 얼마나 중요한 것인지 깨닫게 된다.
이번 포스트에서는 아직 multiprogramming까지는 다루지 않고, 프로세스들 간의 교환이 어떻게 이루어지는지를 먼저 살펴본다.
Scheduling Queue
프로세스가 시작되고 초기화가 완료되면, 해당 프로세스는 먼저 ready queue
에 진입하여 cpu core을 점유할 때 까지 (running 상태) 기다린다. 또한 어떤 특정 이벤트 (ex. I/O interrupt)가 발생하기를 기다리는 프로세스의 경우, 이들을 wait queue
에 위치시키고 기다리게 한다. 이러한 큐들은 프로세스 컨트롤 블록 (PCB)의 Linked List로 구현할 수 있겠다.
제일 위의 ready queue를 살펴보면, PCB 7번이 먼저 실행되고 이후 PCB 2번이 실행됨을 알 수 있다.
아래 네 개의 linked list는 각각이 device와 연결된 wait queue인데, disk I/O를 기다리는 PCB 3번, 14번, 6번이 차례대로 대기하고 있음을 알 수 있다. 바로 아래에는 terminal I/O를 기다리고 있는 PCB 5번도 보인다.
Queueing Diagram
프로세스 스케쥴링을 표현하는 대표적인 방법이 바로 Queueing Diagram이다. cpu와 ready queue, 그리고 각 device에서의 I/O를 기다리는 wait queue들간의 관계를 표시해 두었다. 아래 그림을 해석해 보자.
먼저, ready queue에 있던 프로세스는 cpu를 획득하여 running 상태가 된다. 이때, 별 일 없이 프로세스가 마무리된 후 cpu를 빠져나가 terminate 될 수도 있다. 이제, 그렇지 않은 아래 경우를 보자.
- I/O request가 들어오면, 해당 프로세스는 I/O queue에서 waiting 상태가 된다. 이후 I/O가 마무리되면 다시 ready queue로 들어가서 대기한다.
- time slice expired는 특정 단위의 시간을 정하고, 해당 시간이 지나면 자동으로 expired 처리를 하여 running 중의 프로세스를 중지하는 것을 의미한다. 해당 성격의 interrupt는 어떤 이벤트가 발생할 때 까지 기다리는 것은 아니기 때문에, wait queue가 아니라 곧바로 ready queue로 들어가는 것을 확인할 수 있다.
- fork a child는 running 중인 부모 프로세스가 자식 프로세스를 생성했을 때를 의미한다. 생성된 자식 프로세스는 new 상태를 거쳐 ready queue로 들어간다.
- 어떤 interrupt가 발생할 때까지 wait queue에서 기다릴 수도 있다. 해당 interrupt가 발생하면, 이제 프로세스는 wait 상태에서 ready 상태로 바뀌게 된다.
Context Switch
프로세스의 상태가 running에서 ready로, 그리고 ready에서 다시 running으로 바뀌는 경우를 앞에서 많이 보았다. 우리의 cpu는 단 한순간도 멈춰있으면 안되기에, 해당 프로세스가 ready나 wait상태로 바뀌었다면 이는 다른 프로세스가 cpu를 점유하러 들어갔다는 것을 의미한다. cpu를 두고 프로세스가 마치 교환된 것 처럼 보인다.
문맥 교환 (Context Switch)은 cpu 코어에 다음 프로세스를 배치 및 복원하고, 현재 돌고 있었던 프로세스의 정보를 저장하는 일련의 과정을 의미한다. 문맥 교환을 수행하는 주체는 당연히 운영체제! 그렇다면 문맥은 무엇일까?
프로세스에서의 문맥 (Context)이란, PCB 내에 저장된 정보들을 의미한다. Interrupt가 발생했을 때, 시스템은 running하고 있는 프로세스의 현재 문맥을 저장해 두어야 다음에 다시 running 상태가 되었을 때 문맥을 복원할 수 있을 것이다. 이 때, 제일 중요한 부분이 바로 프로그램이 어디까지 실행되었는지 알고 있는 program counter (pc)이다.
위 그림을 차례대로 해석해 보자.
- 처음에는 0번 process가 cpu를 점유하여 executing 하고 있는 상태였다.
- 그런데 I/O interrupt인지 time expired인지 그런 원인에 의해 더이상 cpu를 점유할 수 없는 상태가 되었다.
- 그 즉시 0번 process의 정보를 담고 있는 0번 PCB에 상태가 저장 (save) 된다.
- 그리고 cpu에는 1번 process의 정보를 담고 있는 1번 PCB가 복원 (reload) 된다.
- 1번 process가 cpu를 점유했고, running 상태가 된다.
- 다시 2번과 같은 interrupt가 발생했고, 마찬가지로 1번 PCB에 정보가 저장된 후 0번 PCB가 다시 복원된다.
- 0번 process가 cpu를 점유하고 running 상태가 된다.
요약
- ready 및 wait queue들은 PCB의 linked list로 구현될 수 있다.
- 프로세스에서의 context는 PCB 내에 저장된 정보를 의미한다.
- context switch는 OS에 의해 진행되며, 각 프로세스의 pc를 저장해 두었다가 다시 실행될 때 복원하는 작업이다.