Uknow's Lab.
article thumbnail

 

 

 

혼공 컴퓨터구조 + 운영체제 4주차

어느덧 벌써 4주차에 접어들었네요.

이제 얼마 남지 않은게 느껴집니다.

 

 

 

운영체제를 알아야 하는 이유

운영체제?

컴퓨터는 전원 플러그만 꽂는다고 작동하는 것이 아닙니다.

운영체제라는 특별한 프로그램의 지휘 하에 작동하는데요.

제가 사용하는 운영체제만 하더라도 윈도우, macOS, Linux, 안드로이드 등이 있습니다.

이외에도 iOS, UNIX, Chrome OS, 퓨시아 등 여러 운영체제들이 있죠.

 

이러한 운영체제들은 1~3주차의 컴퓨터 부품들과 프로그램을 관리하는데 핵심 역할을 합니다.

운영체제는 게임이나 Intellij, 계산기, 브라우저 등과 같은 프로그램으로써 메모리에 적재되어야 합니다.

하지만 운영체제는 매우 특별한 프로그램이므로 항상 컴퓨터가 부팅될 때

메모리 내 커널 영역에 따로 적재되어 실행됩니다.

 

여기서 운영체제가 적재되어있는 커널 영역을 제외한 영역을 사용자 영역이라 합니다.

 

다른 워드 프로세스, 브라우저, 메모장 등은

운영체제가 메모리 주소가 겹치지 않게 적당한 공간에 배치시킵니다.

더 이상 실행되지 않을 경우 메모리에서 삭제하는 역할까지 하죠.

 

 

메모리 관리뿐만 아니라 어떤 프로그램에게

CPU를 먼저 사용할 것인지, 얼마나 오래 사용할 것인지 역시 운영체제가 관리합니다.

한 프로그램이 지나치게 오래 사용하면 다른 프로그램은 정상적으로 실행할 수 없으니,

최대한 공정하게 CPU 자원을 분배합니다.

 

 

 

운영체제를 알아야 하는 이유

1과 2를 더하는 코드를 작성해봅시다. 단, 운영체제가 없다는 가정하에요.

프로그램을 메모리에 적재하는 코드...

 CPU에게 1과 2를 더하게 하는 코드....

모니터에 계산 결과를 출력하는 코드......

모두 개발자의 몫입니다.

 

하지만 운영체제가 있는 세상에서는 하드웨어 조작 및 관리를 운영체제가 도와줍니다.

그럼, 운영체제를 왜 알아야 할까요?

 

우리가 만든 프로그램을 실행시키는 것은 결국 하드웨어입니다.

그리고 하드웨어를 조작하는 프로그램은 운영체제이지요.

운영체제를 깊이 이해한다면

문제 해결의 실마리를 찾을 수 있습니다.

운영체제를 더 잘 알게되면,

운영체제에 더 자세히 명령을 내릴 수 있습니다.

 

 

 

운영체제의 큰 그림

운영체제의 심장: 커널

커널은 운영체제의 핵심 서비스를 담당하는 부분입니다. 자원에 접근하고, 조작하는 일을 하죠.

운영체제가 설치된 모든 기기엔 커널이 있습니다.

커널은 사람의 심장, 자동차의 엔진에 비유할 수 있을 것 같아요.

 

운영체제를 지칭할 때 특별한 언급을 하지 않는 한 커널을 지칭한다 해도 무방합니다.

 

 

이중 모드와 시스템 호출

운영체제는 사용자가 프로그램이 하드웨어에 직접 접근하는 것을 방지합니다.

프로그램이 CPU, 메모리, 하드웨어에 마음대로 접근한다면

자칫 잘못한다면 아주 큰 참사를 불러올 수 있기 때문이죠.

 

때문에 프로그램이 자원에 접근할 때 항상 운영체제를 통해 접근해야 합니다.

비서같은 느낌이려나요.

 

 

운영체제의 역할은 이중 모드로 구현되는데,

이중 모드란 사용자 모드 / 커널 모드로 구분하는 방식입니다.

 

사용자 모드는 커널 영역의 코드를 실행할 수 없는 모드이며,

일반 응용프로그램은 기본적으로 사용자 모드로 실행됩니다.

사용자 모드로 실행되는 프로그램은 자원에 접근할 수 없습니다.

 

반면 커널 모드는 커널 영역의 코드를 실행할 수 있는 모드입니다.

자원에 접근하는 명령어를 포함해 모든 명령어를 실행할 수 있습니다.

 

이때 사용자 모드로 실행되는 프로그램이 커널 모드로 전환하려면

운영체제 서비스를 제공받기 위한 요청, 시스템 호출(시스템 콜)을 해야 합니다.

 

 

시스템 호출은 일종의 소프트웨어 인터럽트로써

시스템 호출이 발생한다면

CPU는 지금까지 작업을 백업 ->

시스템 호출 수행 코드 실행 ->

기존 실행하던 응용프로그램으로 복귀합니다.

 

 

 

 

프로세스와 스레드

프로세스 확인해보기

앞서 말했듯이, 하드디스크에 소스코드 등으로 저장되있는 프로그램이

메모리를 할당받아 실행되면 이를 프로세스라 표현합니다.

 

 

작업관리자를 켜보면 실행중인 프로세스들을 확인할 수 있습니다.

위 프로그램의 공통적은 눈에 보이는 프로세스들이라는 점 입니다.

사용자가 보는 앞에서 실행되기 때문에 포그라운드 프로세스(Foreground Process)라고 합니다.

 

하지만 사용자의 눈에 보이지 않는, 뒷 편에서 실행되는 프로그램도 있습니다.

이를 백그라운드 프로세스(Background Process)라고 합니다.

백그라운드 프로세스 중에서는 사용자와 직접 상호작용 하는 종류도 있지만,

사용자와 상호작용 없이 묵묵히 자신의 일만 하는 프로세스들도 있습니다.

이를 UNIX OS계에서는 데몬(Daemon), Windows에서는 서비스(Service)라 합니다.

 

 

 

프로세스 제어 블록

모든 프로세스는 CPU를 필요로 하나, CPU 자원은 제한되어 있습니다.

때문에 CPU를 번갈아가며 짧은 시간동안 쓰고 인터럽트가 발생하면 다음 프로세스로 토스합니다.

 

이를 위해 운영제체는 프로세스 제어 블록(PCB, Process Control Block)을 이용하는데,

상품에 달린 태그 역할을 하며 해당 상품(프로세스)를 식별하기 위한 정보를 담고 있습니다.

 

PCB는 커널 영역에 생성되며,

점원이 태그를 보고 상품을 식별하듯이

운영체제는 PCB로 프로세스를 식별합니다.

 

프로세스 ID

PID(Process ID)는 특정 프로세스를 식별하기 위해 부여된 번호입니다. 말 그대로 ID인 셈이죠.

 

레지스터 값

프로세스는 자신의 실행 차례가 오면 이전까지 사용했던 레지스터의 중간값들을 모두 복원합니다.

PCB안에는 프로세스가 사용한 프로그램 카운터와  같은 레지스터 값이 담깁니다.

 

프로세스 상태

현재 프로세스가 CPU를 사용하기 위해 기다리는 중인지, CPU를 사용중인지 등의 상태 역시

PCB에 저장됩니다.

 

CPU 스케줄링 정보

프로세스가 언제, 어떤 순서로 CPU를 할당받을지 정보 역시 저장됩니다.

 

메모리 관리 정보

프로세스마다 메모리에 저장된 위치가 다르므로, 이에 대한 정보 역시 필요하죠.

 

사용한 파일과 입출력장치 목록

어떤 입출력장치가 할당되었는지, 어떤 파일을 열었는지에 대한 정보 역시 필요합니다.

 

 

 

문맥 교환

CPU는 여러 프로세스를 번갈아가며 실행한다고 하였죠?

하지만 우리는 한 일을 하다가 다른 일을 하면 이전에 했던 일을 잘 기억하고 있을까요?

정신이 산만해져서 이 일 저 일을 번갈아가며 하면 집중력이 떨어지기 마련이죠.

 

CPU 역시

바로 직전까지 실행되는 프로세스 A의 프로그램 카운터... 레지스터 값... 메모리 정보.... 사용한 파일.... 등

여러 정보를 백업해놨다가 다음 차례가 왔을 때 다시 열어봐야 합니다.

 

수행을 재개하기 위해 기억해야 할 정보를 문맥(context)라 하는데,

이는 PCB에 저장되어 있습니다.

 

 

프로세스 A를 하다가 프로세스 B 차례가 와서 A를 백업해놓은 뒤, B의 정보를 열람하는 이러한 과정을

문맥 교환(Context Switching)이라 합니다.

 

여러 프로세스의 context가 빠르게 갈아끼워지며

여러 프로세스가 동시에 실행되고 있는 것 처럼 보입니다.

 

 

하지만, 이러한 컨텍스트 스위칭에도 자원(시간을 포함한)이 소비되기 마련이기에

너무 빈번한 컨텍스트 스위칭은 오버헤드가 발생할 수 있습니다.

 

 

 

프로세스의 메모리 영역

 

커널 영역에는 PCB가 생성됩니다.

그럼 사용자 영역에는 뭐가 생성될까요?

 

코드 영역

코드 영역 혹은 텍스트 영역은 기계어로 이뤄진 명령어가 저장됩니다.

데이터가 아닌 CPU가 사용할 명령어가 담겨있기 때문에 쓰기가 금지되어 있습니다. Read-only인 셈이죠.

 

데이터 영역

데이터 영역은 잠깐 쓰고 지울 데이터가 아닌,

프로그램이 실행되는 내내 사용할 데이터가 저장됩니다. 전역변수가 대표적이죠.

 

명령어는 사실상 중간에 바뀔 일이 없고,

데이터 영역에 저장될 내용은 프로그램이 실행되는 동안만 유지될 데이터이기에

크기가 고정된 정적 할당 영역입니다.

 

힙 영역

힙 영역은 프로그래머가 직접 할당할 수 있는 영역으로,

메모리를 할당했다면 반드시 해당 공간을 반환해야 합니다.

메모리 공간을 반환하지 않는다면 메모리 내에 할당한 공간이 남아있어

흔히 메모리 누수라 부르는, 메모리 낭비 현상이 발생합니다.

 

자바의 경우, 가비지 컬렉터가 더 이상 사용하지 않는 메모리를 회수하기 떄문에

C/C++에 비해 메모리 관리를 해줄 일이 적으나,

그렇다고 해서 자바가 완전히 메모리 누수에서 자유로운 것은 아닙니다.

 

스택 영역

스택 영역은 데이터를 일시적으로 저장하는 공간으로,

데이터 영역에 비해 잠깐 쓰다가 말 값들이 저장됩니다.

매개 변수 혹은 지역 변수가 대표적이죠.

저장할 데이터는 스택에 PUSH 되고, 필요하지 않다면 POP으로 스택 영역에서 사라집니다.

 

힙 영역과 스택 영역은 실시간으로 그 크기가 변할 수 있기 때문에

동적 할당 영역이라고 합니다.

 

힙 영역은 메모리의 낮은 주소 -> 높은 주소로 할당되고,

스택 영역은 메모리의 높은 주소 -> 낮은 주소로 할당됩니다.

그래야 서로의 데이터가 쌓여도 새로 할당되는 주소가 겹칠 일이 없으니까요.

 

 

 

프로세스 상태와 계층 구조

프로세스 상태

윈도우 사용자가 가장 무서워할 상황. '응~ 답없음~~'

 

프로세스들은 실행 중/실행 중단 등 각자 저마다의 상태가 있습니다.

운영체제는 이런 상태를 PCB에 기록해 관리하죠.

 

대표적인 프로세스의 상태를 알아볼까요?

 

생성 상태(new)

프로세스를 생성 중인 상태를 생성 상태(new)라 하는데,

바로 실행되는 것이 아닌 CPU의 할당을 기다립니다.

 

준비 상태(ready)

당장이라도 CPU를 할당받아 실행할 수 있지만,

아직 자신의 차례가 오지 않아 기다리는 상태입니다.

 

실행 상태(running)

CPU를 할당받아 실행 중인 상태입니다.

할당된 시간동안만 CPU를 사용하며

시간이 끝나면 다시 준비 상태로 돌아갑니다.

실행 중 입출력장치를 사용해 입출력장치의 작업이 끝날 때 까진 대기 상태가 됩니다.

 

대기 상태(blocked)

프로세스가 실행 중 입출력장치를 사용하여 입출력장치 작업이 끝나길 기다리는 상태입니다.

 

종료 상태(terminated)

프로세스가 종료된 상태입니다. 운영체제는 프로세스가 사용한 PCB와 메모리를 정리합니다.

 

 

 

 

프로세스 계층 구조

프로세스는 실행 중 다른 프로세스를 실행할 수 있습니다.

이때 새 프로세스를 생성한 프로세스를 부모 프로세스, 생성된 프로세스를 자식 프로세스라 합니다.

 

물론, 둘은 엄연히 다른 프로세스이며 서로 다른 PID를 가집니다.

일부 운영체제에서는 자식 PCB에 부모 프로세스의 PID인 PPID(Parent PID)가 기록되기도 합니다.

 

자식 프로세스는 또 다른 자식 프로세스를 만들 수도 있고,

자식의 자식 프로세스는 또 다른 자식 프로세스를 만들 수도 있죠.

많은 운영체제는 이러한 계층 구조로써 프로세스를 관리합니다.

 

 

예를 들어 사용자가 컴퓨터를 켠 후, 어느 최초 프로세스가 실행되며,

최초 프로세스는 로그인 프로세스를 생성하고,

로그인 프로세스는 bash 셸을 자식 프로세스로 또 생성하고,

bash 셸은 Vim 프로세스를 생성하는 것처럼요.

 

재밌네요.
그러면 모든 프로세스의 최상위 노드인 최초의 프로세스는 뭐죠?

-> 유닉스 계열에서는 init,
리눅스 계열에서는 systemd,
macOS에서는 launchd라고 하는데요.
이들의 PID는 항상 1이며, 모든 프로세스의 최상단에 있는 부모 프로세스입니다.

 

 

 

프로세스 생성 기법

부모 프로세스를 통해 생성된 자식 프로세스들은 "복제와 옷 갈아입기"를 통해 실행됩니다.

부모 프로세스는 fork를 통해 자신의 복사본을 자식 프로세스로 생성해내고,

만들어진 복사본(자식 프로세스)는  exce를 통해 자신의 메모리 공간을 다른 프로그램으로 교체합니다.

 

 

부모가 자식 프로세스를 생성하며 계층 구조를 이루는 과정은

fork와 exec과 반복되는 과정으로 볼 수 있습니다.

 

부모 프로세스로부터 자식 프로세스가 복제되고,

자식 프로세스는 새로운 프로세스로 옷을 갈아입고,

자식 프로세스로부터 또 다른 자식 프로세스가 복제되고,

또 다시 옷을 갈아입는 과정이 반복되며 계층적으로 실행됩니다.

 

 

 

스레드

스레드(Thread)는 프로세스를 구성하는 실행의 흐름 단위입니다.

프로세스는 여러 개의 스레드를 가질 수 있으며,

하나의 프로세스에서 여러 부분을 동시에 실행할 수 있습니다.

 

 

다크소울3에 군다가 있다면 프로그래밍 언어에는 포인터(C/C++), 객체지향, 스레드가 있다

 

 

스레드는 포인터(C/C++), 객체지향과 함께

프로그래밍 언어를 처음 배우는 입문자들에게

벽을 느끼게 하는 뉴비 절단기 3대장 중 하나라고 생각합니다...

 

다른 두 놈도 그렇겠지만, 스레드는 입문도 어렵고 정복도 어려운데요.

동시성 프로그래밍을 위해 코틀린 코루틴을 사용했을 때,

자바 입문서에서 배운 스레드는 완전 겉핥기였음을 느꼈던 것 같아요. 🤣

 

 

 

프로세스와 스레드

 

프로세스는 한 번에 하나의 일만 처리했습니다.

웹 브라우저, 게임, 워드 프로세스 등은 프로세스가 하나의 실행 흐름을 가지고 한 번에 하나의 부분만 실행되었죠.

 

하지만 스레드(Thread)라는 개념이 도입되면서

하나의 프로세스가 한 번에 여러 일을 동시에 처리할 수 있게 되었습니다.

즉, 스레드는 프로세스를 구성하는 실행 단위라고 할 수 있는데요.

 

 

스레드는 프로세스 내에서 각기 다른 스레도 ID, 프로그램 카운터, 스택으로 구성되며

때문에 각기 다른 코드를 실행할 수 있습니다.

 

중요한 점은 스레드들은 최소한의 정보(프로그램 카운터, 레지스터, 스택)만을 가지고
프로세스 자원을 공유하며 실행된다는 점 입니다.

스레드 1만의 코드/데이터/힙 영역이 있고,
스레드 2만의 코드/데이터/힙 영역이 존재하는 게 아닌거죠.

 

 

 

다만, 모든 운영체제가 스레드와 프로세스를 명확히 구분하는 것은 아닙니다.

리눅스는 프로세스와 스레드 모두 "실행의 문맥"이라며 Task라는 이름으로 통일해 부릅니다.

"프로세스와 스레드의 개념을 조금 더 명확이 구분지을 필요가 있다"는 말에 대한 리누스 토르발스(리눅스 창시자)의 답변

 

 

 

멀티 프로세스와 멀티 스레드

컴퓨터는 실행 과정에서 여러 프로세스가 동시에 실행될 수 있고,

그 프로세스를 이루는 여러 스레드가 동시에 실행될 수 있습니다.

 

여러 프로세스를 동시에 실행하는 것을 멀티 프로세스(Multiprocess),

여러 스레드로 프로레스를 동시에 실행하는 것을 멀티스레드(Multithread)라고 합니다.

 

 

 

그럼 동일한 작업을 수행하는데 있어

멀티프로세스와 단일프로세스+멀티스레드로 실행하는 것은 무엇이 다를까요?

 

프로세스끼리는 자원을 공유하지 않지만,

스레드끼리는 자원을 공유합니다.

 

프로세스를 fork하여 같은 작업을 하는 동일 프로세스를 만들면

코드 영역, 데이터 영역, 힙 영역 등 모든 자원이 복제되어 메모리에 적재되나,.

스레드는 서로 다른 스레드 ID, 프로그램 카운터, 레지스터 값, 스택을 가질 뿐,

프로세스가 가지고 있는 자원을 공유합니다.

 

즉, 여러 프로세스를 병행 실행하는 것 보다

더 효율적이고 가벼운 것이죠.

또한, 프로세스는 서로 자원을 공유하지 않나 남남같은 관계이지만,

스레드는 자원을 공유하기 때문에 서로 협력과 통신에 유리합니다.

 

 

 

물론 프로세스의 자원을 공유한다느 점이 장점만 있는 것은 아닙니다.

멀티 프로세스에서는 한 프로세스에 문제가 생겨도 다른 프로세스에는 영향이 적거나 없지만,

멀티스레드 환경에서는 한 스레드에 문제가 생긴다면 프로세스 전체의 문제로 이어질 가능성이 있습니다.

모든 스레드가 하나의 자원을 공유하기 때문입니다.

 

 

이를 가장 잘 나타내는 예시는 브라우저입니다.

저는 네이버 웨일 브라우저를 사용하고 있는데요.

 

네이버 웨일(구글 크롬도 동일)의 탭 하나하나는 스레드가 아닌 각기 다른 프로세스로써,

애플리케이션 자체에 영향을 끼칠만큼 치명적인 오류가 아닌 이상

한 탭에 문제가 생겨도 다른 탭에 영향이 없거나 적습니다.

 

작업관리자를 띄워보면 수많은 Whale 프로세스가 실행되고 있음을 볼 수 있습니다.

 

 

 

CPU 스케줄링 개요

모든 프로세스는 CPU를 필요로 합니다.

때문에 운영체제는 CPU를 최대한 공정하게 배분해야 합니다.

이를 CPU 스케줄링이라 하는데요.

 

CPU를 잘 배분하지 못하면 한 프로세스만 독점적으로 CPU를 사용해,

다른 프로세스는 CPU를 사용하지 못하는 상태가 될 수 있습니다.

 

 

 

프로세스 우선순위

CPU를 사용하는 순서를 정하는 가장 간단한 방법은

맛집 웨이팅과 같이 먼저 온 순서대로 CPU를 배분하는 것입니다.

큐(Queue)의 선입선출(FIFO: First In First Out) 방식과 동일하죠.

 

굉장히 간단하지만

CPU를 우선하여 배분해야 하는 프로세스들이 있습니다.

 

대부분 프로세스는 실행 - 대기 - 실행 - 대기를 반복하게 됩니다.

그리고 프로세스 종류에 따라 입출력장치를 이용하는 시간과 CPU를 이용하는 시간의 양에는 차이가 있죠.

 

비디오 재생/ 디스크 백업 등 입출력 작업이 많은 프로세스 입출력 집중 프로세스와,

수학 연산, 컴파일 등 CPU 작업이 주인 CPU 집중 프로세스도 있습니다.

 

전자의 경우, 입출력이 많기 때문에 입출력을 위한 대기 상태에 더 많이 머무르며,

후자는 대기 상태보다는 실행 상태에 더 많이 머무르게 됩니다.

때문에 모두 동일한 비율로 CPU를 사용하는 건 비효율적인 것이죠.

 

CPU 집중 프로세스와 입출려 집중 프로세스가 동시에 CPU 자원을 요청했을 때,

입출력 집중 프로세스는 어차피 대기 상태가 될 것이기에

가능한 빨리 입출력 집중 프로세스에 CPU를 할당해주고,

그 다음 CPU 집중 프로세스에 CPU를 할당해주는게 좋죠.

입출력 집중 프로세스를 먼저 처리해버리면 다른 프로세스가 CPU를 사용할 수 있으니까요.

 

때문에 운영체제는 프로세스마다 우선순위(Priority)를 부여합니다.

 

 

 

스케줄링 큐

운영체제는 각 프로세스들에게 줄을 세웁니다. 이를 스케줄링 큐(Scheduling Queue)라 합니다.

(스케줄링의서의 Queue는 무조건 선입선출(FIFO)이여야 필요는 없습니다.)

 

 

운영체제는 대부분 자원을 큐로 관리하며,

큐의 종류는 다양하나 대표적으로 준비 큐와 대기 큐가 있습니다.

 

 

준비 큐는 CPU를 이용하고 싶은 프로세스들이 줄을 서는 큐이며,

대기 큐는 입출력장치를 이용하기 위해 대기 상태에 접어든 프로세스들이 줄을 서는 큐입니다.

 

 

선점형과 비선점형

한 프로세스가 CPU를 이미 사용하고 있을 때,

다른 급한 프로세스가 와서 CPU를 사용하길 요청하면 어떻게 할까요?

 

여기에는

CPU를 사용중인 프로세스로부터 CPU를 뺏어와

급한 프로세스에게 CPU를 주는 선점형 스케줄링과,

 

CPU를 사용중인 프로세스가 끝날때까지 기다리게 하는

비선점형 스케줄링이 있습니다.

 

선점형 스케줄링(Preemptive Scheduling)은 이름에서 알 수 있듯이,

CPU를 이미 사용중인 프로세스로부터 CPU를 빼앗아 급한 프로세스에게 넘여줍니다.

어느 하나의 프로세스가 자원을 독점할 수 없는 방식이죠.

한 프로세스의 자원 독점을 막고 골고루 자원을 배분하지만

컨텍스트 스위칭 과정에서 오버헤드가 발생할 수 있습니다.

 

반면 비선점형 스케줄링(Non-preemptive Scheduling)은

하나의 프로세스가 자원을 사용하고 있다면

해당 프로세스가 종료 / 대기 상태에 접어들기 전 까진 다른 프로세스가 끼어들 수 없습니다.

자원을 독점하는 방식이죠.

컨텍스트 스위칭 중 오버헤드는 선점형에 비해 적지만,

모든 프로세스가 골고루 자원을 사용할 수 없습니다.

 

현재 대부분 운영체제에서는 선점형 스케줄링 방식을 채택하고 있습니다.

 

 

 

CPU 스케줄링 알고리즘

CPU가 스케줄링에 사용하는 알고리즘은 매우 다양한데요.

중요한건 각 스케줄링에 사용된 '아이디어'지 '용어'가 아닙니다.

용어 자체보다는 각 스케줄링 알고리즘의 아이디어와 그 장단점을 아는게 중요하죠.

 

 

선입 선처리 스케줄링

선입 선처리 스케줄링 혹은 FCFS(First Comed Served Scheduling)은

단순히 준비 큐에 온 순서대로 프로세스를 처리하는 비선점형 스케줄링입니다.

가장 공평해보이긴 하지만, 때때로 프로세스의 대기 시간이 매우 길어질 가능성이 있죠.

 

A프로세서가 5ms, B프로세스가 10ms, C 프로세스가 2ms를 실행할 때,

A - B - C 순서대로 왔다면 C 프로세스는 고작 2ms를 실행하기 위해 15ms를 기다려야 합니다.

이런 현상을 호위 효과(Convoy Effect)라 합니다.

 

최단 작업 우선 스케줄링

호위 효과를 방지하기 위해서는 간단히 생각하자면

CPU 사용 시간이 짧은 것 부터 처리하는 방식이 좋을 것 같습니다.

이러한 방식을 취단 작업 으선 스케줄링 혹은 SJF(Shortest Job First Scheduling)이라 합니다.

기본적으로 비선점형이나, 선점형으로 구현될 수도 있습니다.

다만, 이 방법도 실행 시간이 긴 프로세스는 매우 오래 기다려야 할 수도 있습니다.

 

라운도 로빈 스케줄링

라운도 로빈(Round Robin) 스케줄링은 선입 선처리 + 타임 슬라이스 방식입니다.

각 프로세스가 CPU를 사용할 수 있는 시간을 정해놓고

해당 시간이 지나면 다음 프로세스에게 CPU를 넘기는 선점형 방식이죠.

 

당연하게도 사용시간(타임 슬라이스)의 길이가 매우 중요한데,

지나치게 크면 사실상 FCFS랑 다를 바 없고

지나치게 작으면 컨텍스트 스위칭으로 오버헤드가 많이 발생합니다.

 

최소 잔여 시간 우선 스케줄링

이름도 어렵습니다.

최소 잔여 시간 우선 스케줄링 / SRT(Shortest Remaining Time) 스케줄링은

최단 작업 우선 스케줄링 + 라운드 로빈입니다.

최소 잔여 시간을 우선으로 스케줄링 하되,

타임 슬라이스가 지나면 다음 프로세스에게 CPU를 넘기는 방식입니다.

이 때 다음 프로세스는 남아있는 작업 시간이 가장 작은 프로세스가 선택됩니다.

 

우선순위 스케줄링

우선순위 스케줄링(Priority Scheduling)은 프로세스들에 우선순위를 부여하며,

우선순위 대로 처리하는 방법입니다. (우선순위가 같을 경우 선입 선처리)

 

하지만 우선순위 스케줄링에는 근본적인 단점이 있는데,

바로 우선 순위가 낮은 프로세스는 높은 우선순위를 가진 프로세스가 계속 삽입될 경우

계속 기다리게 되는 기아(starvation) 현상이 발생할 수 있습니다.

T 익스프레스 타려고 줄 서고 있는데 PASS권 가진 사람들이 내 앞에 계속 추가되는 느낌이죠!

 

이를 방지하기 위한 기법으로 에이징(aging)이 있는데,

대기한 프로세스의 우선순위를 점차 높이는 방식입니다.

마치 나이를 먹듯이(aging)요.

우선순위가 낮더라도 조금씩 우선순위가 올라가 결국 실행될 수 있습니다.

 

다단계 큐 스케줄링

다단계 큐는 우선순위 스케줄링의 업그레이드 형태로,

우선순위 별로 준비 큐를 여러 개 사용하는 방법입니다.

우선순위가 가장 노은 큐에 있는 프로세스를 처리하고,

그 다음 우선순위 큐에 있는 프로세스들을 처리합니다.

 

큐를 여러 개 두어 프로세스 유형별로 우선순위를 구별해 실행하는 것이 편리해집니다.

각 큐별로 타임 슬라이스를 다르게 or 다른 스케줄링 알고리즘을 사용할 수도 있고요.

 

다단계 피드백 큐 스케줄링

다단계 큐와 비슷하지만, 프로세스들이 큐 사이를 이동할 수 있습니다.

에이징 기법을 사용해 우선순위가 낮은 프로세스의 기아 현상을 고려한 것이라 할 수 있습니다.

복잡하지만 가장 일반적인 CPU 스케줄링 알고리즘으로 알려져 있습니다.

 

 

 

과제

1. 304 확인문제 1번

1 - 생성, 2 - 준비, 3 - 실행, 4 - 종료, 5 - 대기

 

2. Ch.11(11-2) 준비 큐에 A,B,C,D 순으로 삽입되었다고 가정했을 때, 선입 선처리 스케줄링 알고리즘을 적용하면 어떤 프로세스 순서대로 CPU를 할당받는지 풀어보기

선입 - 선처리이니 A - B - C - D 온 순서대로 처리

 

 

 

후기

저학년때는 너무 어려웠던 것들이지만

지금와서 다시 보니 술술 읽히는게 감회가 새롭네요.

 

기술 면접 시간때 받아본 질문에 관한 내용도 여럿 있어서

특히 재밌게 읽은 부분이였던 것 같습니다.

기술 면접에 떨어지고 나서 칼을 갈며 공부한 파트라

잠시 '아 너무 쉽네~'라는 생각이 들었는데...

뒷 부분을 슬쩍 엿보니 운영체제가 아주 큰 빠다를 들고 기다리고 있길래 바로 저의 오만함을 반성했습니다.

5~6주차가 두렵네요.

profile

Uknow's Lab.

@유노 Uknow

인생은 Byte와 Double 사이 Char다. 아무말이나 해봤습니다.