우아한테크코스에서 CS 스터디를 진행중에 있는 저는, 9월 2주차 발표 주제로 운영체제가 여러 프로그램을 동시에 실행하는 원리에 대해 설명해주세요.
라는 주제를 선택했습니다. 대학교 시절 운영 체제 수업을 들으면서 분명히 배웠는데, 전혀 기억이 안났었기 때문이죠. 이번 기회에 다시 잊어버리지 않도록 운영체제가 동시에 작업을 실행하는 원리에 대해서 공부해보고 정리해 보기로 했습니다.
시작하기에 앞서 주의
책과 대학 시절 전공 자료를 통해 개인적으로 공부한 내용입니다. 틀린 내용이 있을 수 있으니 이 글의 내용을 맹신하지 말아주세요. 또한 프로세스에 대해 어느정도 이해하고 있다는 가정 하에 쓰여진 글입니다.
오늘날 우리가 사용하는 컴퓨터는 한 번에 여러 개의 프로그램을 동시에 실행합니다. 지금 이 글을 쓰는 저도 유튜브로 음악을 틀어놓고 카카오톡 채팅을 보면서 동시에 글을 쓰고 있습니다. 단순히 이 작업들 뿐만 아니죠. 작업 관리자를 켜보면 수많은 프로세스가 동시에 실행되고 있는 것을 확인할 수 있습니다.
이렇게 동시에 여러 작업을 하는 것을 우리는 멀티태스킹(Multitasking)이라 부르곤 합니다. 단순히 컴퓨터에만 쓰이는 용어가 아니라 일상에서도 많이 쓰이는 단어기도 하죠. 어떻게 컴퓨터는 이렇게 여러 가지 작업을 동시에 할 수 있는 걸까요?
사실, 컴퓨터는 여러 작업을 동시에 하고 있는 것이 아닙니다. CPU 하나, 정확히는 CPU의 코어 하나가(과거 CPU는 싱글코어였으므로 CPU 하나 = 코어 하나가 맞겠죠?) 한 번에 실행할 수 있는 작업의 수는 하나에 불과합니다. 그렇다면 어떤 마법을 부리길래 우리가 보기에는 여러 프로그램이 동시에 실행되고 있는 것일까요? 바로 여러 작업을 번갈아면서 조금씩 빠르게 처리하여 동시에 처리되고 있는 것 처럼 보이게 하는 방법
을 사용해서입니다.
예를 하나 들어볼까요? 저와 제 조금 윗 또래분들의 어릴 적 가슴을 설레게 했던 스타크래프트라는 게임을 해보면, 병력 생산과 생산된 병력의 컨트롤을 동시에 하는 멀티태스킹 능력이 굉장히 강조된다는 것을 알 수 있습니다. 이걸 얼마나 잘하냐가 초보와 고수의 차이를 가리는 기준이 되기도 하죠. 그런데, 사실 병력 생산은 생산대로, 컨트롤은 컨트롤대로 한 번에 한 가지 일 밖에 못하는 것 아닌가요? 그런데도 우리는 마치 둘을 동시에 진행하는 것 같이 생각합니다. 그건 바로 매우 짧은 시간동안 생산과 컨트롤을 빠르게 오가면서 진행하기 때문입니다.
본진에서 SCV를 뽑으면서 동시에 저글링을 피해 정찰간 SCV를 컨트롤하는 이영호의 손놀림을 봅시다. 사실 생산 -> 컨트롤 -> 생산 -> 컨트롤 순으로 작업을 바꿔가면서 할 뿐인데, 워낙 빠르게 오가다 보니 우리는 이걸 생산과 컨트롤을 동시에 한다
고 하죠.
컴퓨터의 멀티태스킹 역시 마찬가지입니다. CPU의 매우 빠른 연산 속도를 이용하여 한 가지 일을 하다가 멈추고, 다른 일을 진행하고, 다시 멈추고, 다시 다른 일을 진행하고... 여러 일을 빠르게 바꿔가면서 마치 동시에 일어나는 것처럼 우리 눈을 속입니다. 이렇게 여러 작업을 조금씩 처리하여 동시에 처리되는 것처럼 보이게 하는 것을 시분할 시스템(Time Sharing System) 또는 다중 작업(Multitasking) 이라 합니다. 시분할 시스템이 고안되기 전에는 한 번에 한 가지 작업을 하고 프로그램 실행 중간에 사용자가 데이터를 입력하거나 수정하는 것이 불가능한 일괄 작업 시스템(batch job system)을 사용했고, 지금도 윈도우의 .bat 파일 등으로 그 흔적이 남아 있습니다.
물론 현재 컴퓨터는 동시에 하나의 작업만 처리하지는 않습니다. 현재는 CPU의 코어가 많아지면서 실제로 동시에 여러 개의 작업이 처리될 수 있습니다. 하지만 기껏해야 8개 정도까지인 CPU의 코어 개수로 수십, 수백 개의 프로세스를 모두 한 번에 처리할 수는 없고, 결과적으로 여전히 각각의 CPU 코어들은 시분할 시스템으로 프로그램들을 처리하고 있는 것이죠.
여러 작업을 번갈아가면서 처리해서 동시에 진행되는 것처럼 보이게 하는 것은 좋은데, 효과적인 멀티태스킹을 하려면 언제 어떤 프로세스를 실행시킬지 결정하는 것이 매우 중요하지 않을까요? 이렇게 작업 처리 순서를 결정하는 것을 스케줄링이라고 합니다.
스케줄링은 운영체제가 프로세스 처리에 할당되었던 CPU를 다시 뺏어올 수 있는가 없는가에 따라 선점형과 비선점형 스케줄링으로 나뉩니다.
비선점형 스케줄링은 운영체제가 CPU의 사용을 뺏어올 수 없기 때문에, 실행 중인 프로세스가 있다면 다른 프로세스를 할당할 수 없습니다. 즉, 실행 중인 프로세스가 대기 상태가 되거나 종료되지 않는 한 프로세스를 전환할 수 없습니다. 반면 선점형 스케줄링은 운영체제가 자체적으로 판단하여 다른 프로세스를 실행해야 한다면 CPU가 다른 프로세스를 실행하도록 할 수 있습니다.
선점
과 비선점
때문에 용어가 매우 헷갈리는 부분입니다. 오히려 비선점 스케줄링이 이미 CPU를 선점
하고 있으니까 프로세스가 끝나기 전까지는 다른 프로세스를 실행시킬 수 있다는 느낌 같기 때문이죠. 어쨌든 비선점
의 경우에는 실행중인 프로세스가 자발적
으로 주도권을 내놓지 않는 한 운영체제가 CPU를 뺏어올 수 없는 것을 의미하고 선점
의 경우에는 강제로
뺏어올 수 있는 것을 의미한다고 생각하면 될 것 같습니다.
비선점 스케줄링의 경우 선점 방식에 비해 스케줄러 호출 빈도가 낮고 컨텍스트 스위칭(뒤에서 설명하겠습니다) 빈도도 낮기 때문에 그만큼 오버헤드가 적다는 장점이 있겠죠? 하지만 한 작업이 끝날 때 까지 기다려야 하니 일괄 처리 방식에 좀 더 어울린다고 볼 수 있습니다.
하지만 앞서 운영체제는 시분할 시스템을 사용한다고 했는데, 그렇다면 작업이 다 끝나지 않았음에도 운영체제가 지정한 시간이 다 되었다면 프로세스로부터 CPU 사용권을 뺏어와야겠죠? 그렇기 때문에 시분할 시스템에서는 선점형 스케줄링을 사용합니다.
시분할 시스템을 사용한다고 한다면 당연히 각각의 작업에 얼마씩의 시간을 할당할 것인지 정할 필요가 있습니다. 이렇게 다른 프로세스에 CPU를 뺏기기 전까지 얼만큼 일을 할 지 시간 단위를 타임 슬라이스, 또는 타임 퀀텀 이라고 합니다.
타임 슬라이스의 크기는 어떻게 결정할까요? 만약 타임 슬라이스가 너무 크면 타임 슬라이스 안에 작업을 다 처리해 버리니까 사실상 FIFO(First In First Out) 방식과 같게 되어 시분할 시스템을 사용하는 의미가 없겠죠. 그렇다면 타임 슬라이스를 무작정 작게 하면 되지 않을까요? 타임 슬라이스가 작으면 작을수록 더 동시에 진행하는 것처럼 보일테니 말이죠. 하지만 타임 슬라이스가 작으면 작은 대로 문제가 발생합니다.
앞에서도 살짝 언급했지만, 컨텍스트 스위칭
이라는 것이 있습니다. 프로세스를 교체할 때 기존에 실행되던 프로세스의 값들을 모두 날릴 수는 없으니 PCB라는 자료구조에 저장하고, 실행할 프로세스의 값들을 PCB에서 가져와 교체하는 작업을 진행하는데 이것을 컨텍스트 스위칭이라고 합니다. 컨텍스트 스위칭에도 연산이 필요하고 시간이 필요하므로 이 과정에서 오버헤드가 발생하게 됩니다. 당연하게도, 타임 슬라이스가 작으면 작을수록 더 많은 컨텍스트 스위칭이 일어나므로 오버헤드가 발생하게 됩니다.
그래서 타임 슬라이스를 스케줄링이 효과적이도록 적정 크기로 설정할 필요가 있습니다. 경험의 법칙(rule of thumb)에 의하면, 전체 CPU burst(프로그램 실행 중에 연속적으로 CPU를 사용하는 단절된 구간, 즉 CPU가 연산을 시작한 뒤 IO로 인해 연산을 멈추기 전까지의 구간)중 80% 정도가 타임 슬라이스보다 작도록 타임 슬라이스의 크기를 정해야 한다고 합니다. 그러니까 80% 정도의 CPU burst가 타임 슬라이스보다 작도록 타임 슬라이스를 설정했더니 가장 좋은 결과가 나왔다
정도로 이해하면 될 것 같습니다. 원래 경험의 법칙이 그런 거거든요
지금까지 운영체제가 여러 프로그램을 동시에 실행하는 방법에 대해 간단히 알아봤습니다. CS라는 녀석은 익숙하지 않은 녀석이라 그런지 정말 공부하면 할수록 어렵네요. 대학교 다닐 때 CS 수업을 좀 더 열심히 들어놓을걸 그랬습니다.
참고 자료
쉽게 배우는 운영체제 - 조성호 저
대학교 시절 운영체제 강의 자료
여러 프로그램이 동시에 실행되는 원리(feat. 운영체제)
스터디 중간과 그 이후 크루들과 이야기를 나누는 과정에서 이야기가 나와서 정리를 해보려고 합니다. 요즘 CPU의 스펙을 보면 4코어 8스레드
, 8코어 8스레드
, 8코어 16스레드
와 같이 쓰여 있는 것을 볼 수 있습니다. 여기서도 스레드
라는 용어를 사용하기 때문에 헷갈리는 경우가 많은 것 같습니다.
앞서 CPU 하나, 정확히는 CPU의 코어 하나가(과거 CPU는 싱글코어였으므로 CPU 하나 = 코어 하나가 맞겠죠?) 한 번에 실행할 수 있는 작업의 수는 하나에 불과합니다.
라고 했습니다. 과거의 CPU들은 코어 하나 당 처리할 수 있는 스레드의 수가 하나였으므로 맞지만, 요즘은 그렇지 않습니다. Simultaneous Multi-Threading(동시 멀티스레딩)
, 즉 SMT라는 기술의 도입으로, 이제 코어 하나에서 두 개의 스레드를 처리할 수 있게 되었습니다. 인텔에서 하이퍼스레딩
이라고 홍보하는 기술이 바로 그것이죠.
때문에 CPU 스펙을 읽을 때는 이렇게 생각하면 됩니다.
코어 라고 쓰여 있는 쪽이 실제 CPU의 코어 개수, 논리 프로세서라고 쓰여 있는 값이 동시에 실행할 수 있는 스레드 개수입니다.
4코어 8스레드
즉, 제 CPU는 동시에 8개의 작업을 처리할 수 있으며, 실제로 돌아가고 있는 스레드는 그보다 무수히 많으므로 운영 체제가 한 번에 8개의 스레드 씩 적절히 스케줄링하여 처리한다고 생각하면 되겠습니다.
오찌~! 아주 정성스러운 글을 올리셨군요?!
연휴에 공부하랴 글 작성하랴 고생하셨습니다 👍🏻
오찌네 CS 스터디가 궁금해지는 글이었어요!
대학교 다닐 때 CS 수업을 좀 더 열심히 들어놓을걸 그랬습니다.
ㄴ 저도요...^^
오랜만에 운영체제 냄새를 맡으니 학교 수업 듣던 때가 생각나고 좋습니다 🫠