※ 본문은 혼자 공부한 내용을 기록한 글입니다. 오개념이 있다면 반드시 댓글로 알려주세요!
[ 1 ] Mainframe
초창기 대형 컴퓨터인 Mainframe은 '사람'이 프로그램이 실행되어야 할 순서대로 펀치카드를 정리하여 제출하면, 그것이 메모리에 적재되어 작업을 순차적으로 처리했다. 일단 한번 시작한 작업은 중단될 수 없었고, 하나의 작업이 끝나야 다음 작업이 수행될 수 있었다. 또한, 펀치카드를 제출하면 결과를 받을 때까지 컴퓨터와 유저 간의 상호작용을 할 수 없었고, 작업을 일괄 처리(Batch)하는 방식이었다.
이는 매우 직관적이고 단순한 OS 개념이었으며 기계적인 I/O 장치와 CPU 사이의 현저한 속도 차로 인해 CPU가 빈번히 idle 상태로 전환되는 문제점이 있었다.
예를 들어, 컴퓨터가 프린터에 특정 자료를 출력해달라고 요청하면 그 프린터의 작업이 끝날 때까지 다른 작업을 수행할 수 없었던 것이다. 그로 인해 CPU 활용률이 현저히 낮았다.
[ 2 ] Spooling
이를 해결하기 위해 Simultaneous Peripheral Operation On-Line (Spooling) 이라는 기법이 도입되었다. 이제 프린터에 하는 요청을 메모리의 버퍼에 로드해놓음으로써 프린터가 자신의 처리 속도로 인쇄를 수행하는 동안 CPU도 연산을 처리할 수 있게 되었다.
Spooling 덕분에 프린터에 출력 요청, 디스크 기록 등의 비동기 IO 작업을 수행하는 동안에는 CPU를 활용할 수 있게 되었지만, CPU 작업이 IO 처리 결과를필요로 하는 '동기 IO'의 경우에는 여전히 IO 처리를 요청한 후 곧바로 다음 CPU 작업을 재개할 수 없었다.
예를 들어, SSD에서 한글 파일을 읽어 오는 경우(일반적으로 read() 작업에 해당)에는 한글 파일을 다 읽어올 때까지 다음 CPU 작업을 할 수 없었던 것이다.
[ 3 ] Automatic job sequencing - Multiprogramming
이를 해결하기 위해 사람이 직접 스케줄링을 하는 것(Batching)이 아니라 스케줄링을 담당하는 소프트웨어가 프로그램을 실행 및 제어하는 Automatic job sequencing 이 등장했다.
Automatic job sequencing에서는 이제 하나의 실행중인 프로그램이 IO 작업을 수행하면 해당 프로그램이 CPU 점유를 놓음으로써, 다른 프로그램이 CPU를 바로 점유할 수 있었다. 즉, Spooling이 동기 IO에서 겪었던 한계를 해결한 것이다.
이러한 Automatic job sequencing을 가능하게 한 구현 기술이 바로 Multiprogramming 이다.
Batch 방식에서는 현재 실행 중인 프로그램만이 전체 memory 를 점유했기에 프로그램이 I/O 작업을 수행하더라도 그 프로그램만 실행될 수 있었다. 하지만, Multiprogramming에서는 전체 memory를 나누어 여러 프로그램이 memory 를 점유하도록 했고, 이를 통해 실행 중인 프로그램이 I/O 작업을 수행하면 memory에 떠 있는 다른 프로그램이 바로 CPU를 점유하여 실행될 수 있었다.
이를 가능하게 한 것이 바로 물리 memory를 가상화한 address space(주소 공간)이었다. OS는 물리 memory를 가상화하여 address space 라는 가상의 주소 공간을 만들었고, 프로세스에 그 가상의 주소 공간을 할당하여 실제 물리적인 메모리 주소와 매핑시켰다. 각 프로세스는 자신이 할당받은 주소 공간에만 접근할 수 있었기에 이를 통해 하나의 물리 메모리에 여러 프로세스가 떠 있어도 각 프로세스의 상호 간섭을 방지하고 독립성을 보장할 수 있었다.
결과적으로 Multiprogramming은 CPU의 활용률을 극대화할 수 있었다.
하지만, Multiprogramming의 단점은 다른 프로그램이 실행되기 위해서는 현재 실행되고 있는 프로그램이 I/O 작업을 함으로써 스스로 CPU 점유를 놓는 것(이를 voluntary yield라 한다)을 기다려야 했다. 만약, 실행 중인 프로그램이 의도적으로 I/O 작업을 수행하지 않으면 결국 다른 프로그램도 실행될 수 없었던 것이다.
즉, 사용자와 OS는 여전히 '실행 중인 프로그램'에 대해서는 관여할 수 없었고, 프로그램 간의 공평성을 지킬 수 없었던 것이다.
[ 4 ] Time sharing
이를 해결하기 위해 실행 중인 프로그램이 스스로 CPU를 놓을 때까지 기다리는 것이 아니라 CPU의 실행 시간을 타임 슬라이스로 나누어 프로그램들을 실행하는 Time sharing 기법이 등장했다.
만약 타임슬라이스가 10ms 라면 "10ms 동안 A 프로그램이 실행 → 10ms 동안 B 프로그램이 실행 → 10ms 동안 C 프로그램이 실행 → 10ms 동안 A 프로그램이 실행 → ... " 의 순서로 프로그램들이 실행되는 것이다.
실제로는 t라는 순간에 하나의 프로그램만이 실행되고 있는 것이지만, 타임 슬라이스는 매우 짧기 때문에 마치 여러 프로그램이 동시에 수행되는 것처럼 보인다. 우리는 이것을 "Concurrent execution"이라 한다.
(실제로는 하나의 프로그램만이 실행되고 있지만, 여러 프로그램들이 동시에 '수행 상태'에 있다고도 표현한다)
Time sharing으로 Multiprogramming의 단점이었던 '프로그램 간 실행 시간의 공평성'을 해결할 수 있게 되었다.
하지만, Time sharing은 각 타임 슬라이스마다 Context Switch(실행 중이던 프로세스의 state는 저장, 새로운 프로세스를 load하는 과정)가 발생하는데 이는 상당히 무거운 동작이기 때문에 Multiprogramming 보다 성능이 좋지 않다는 단점이 있다.
[ 정리 ]
Multiprogramming | Time sharing |
CPU 활용률 극대화 가능 | OS 정책에 따른 정확한 스케줄링 가능 |
프로세스 간 실행 시간의 공평성 보장 불가 | Context Switch로 인한 성능 오버헤드 발생 |
'CS > 운영체제' 카테고리의 다른 글
[운영체제 OS] 프로세스와 스레드, 그리고 병렬처리 (2) | 2023.06.14 |
---|---|
[운영체제 OS] Monolithic kernel, Micro kernel (1) | 2023.05.08 |
[운영체제 OS] system call 및 호출 루틴 (1) | 2023.04.16 |
[운영체제 OS] 운영체제란? (1) | 2023.04.16 |