켜 둔 프로그램은 수십 개인데, 코어는 몇 개뿐입니다. 어떻게 전부 동시에 도는 것처럼 보일까요? 창구 하나를 여러 손님이 아주 빠르게 번갈아 쓰면, 밖에서 보기엔 모두가 동시에 처리되는 것처럼 보입니다.
기초에서 먼저 보기컴퓨터는 기다리는 동안 다른 일을 할 수 있을까?컴퓨터에는 지금도 수십 개의 프로그램이 켜져 있습니다. 그런데 CPU 코어가 하나뿐이라면, 어떻게 여러 개가 동시에 도는 것처럼 보일까요? 답은 아주 빠른 교대입니다. 이 단원에서는 실행 중인 프로그램 하나하나를 뜻하는 프로세스가 무엇인지, 그리고 운영체제가 왜 굳이 이들을 서로 격리시키는지 봅니다.
프로그램은 디스크에 저장된 명령어 목록, 즉 죽어 있는 파일입니다. 이것을 실행하면 운영체제가 메모리에 올리고, 스택과 힙을 마련하고, PC를 첫 명령에 맞춰 줍니다. 이렇게 살아 움직이는 상태를 프로세스라고 합니다. 같은 프로그램을 두 번 실행하면 프로세스는 두 개가 되고, 둘은 서로 다른 메모리를 씁니다.
프로세스마다 3단원에서 본 스택과 힙을 통째로 한 벌씩 갖습니다. 게다가 운영체제는 각 프로세스에게 "이 메모리는 전부 네 것"이라는 가짜 지도(가상 메모리)를 보여줍니다. 그래서 프로세스 A의 100번지와 프로세스 B의 100번지는 실제로는 완전히 다른 물리 메모리입니다. 덕분에 A가 잘못된 주소를 건드려도 B는 안전합니다. 이 격리가 프로세스의 존재 이유입니다.
운영체제 안에는 "다음엔 누구에게 CPU를 줄까"를 정하는 스케줄러가 있습니다. 어떤 프로세스가 IO를 기다리러 가면 즉시 다른 프로세스를 올리고, 아무도 양보하지 않으면 아주 짧은 시간마다 강제로 교대시킵니다. 이 방식을 시분할이라고 합니다. 아래 애니메이션에서 CPU0 칩이 줄 사이를 옮겨 다니는 것이 그 장면입니다. 동시에 도는 게 아니라, 아주 빨리 갈아타는 것뿐입니다.
프로세스를 하나 만들려면 메모리 공간을 새로 마련해야 하니 비쌉니다. 프로세스끼리 데이터를 주고받으려면 운영체제를 거치는 별도 통신(IPC)이 필요해 번거롭고 느립니다. 교대할 때도 메모리 지도를 통째로 바꿔야 해서 무겁습니다. 이 비용이 다음다음 단원에서 스레드가 태어나는 이유가 됩니다.
프로세스를 만들려면 운영체제는 주소 공간을 마련하고, 페이지 테이블을 세우고, 파일 디스크립터 표를 비롯한 커널 자료구조를 준비해야 합니다. 그래서 프로세스 생성은 뒤에 나올 스레드 생성보다 훨씬 비쌉니다. 그런데 바로 그 준비 덕분에 프로세스 하나가 잘못돼도 다른 프로세스는 멀쩡합니다. 비싼 이유와 안전한 이유가 정확히 같은 것입니다.
무겁다고 해서 프로세스가 사라진 것은 아닙니다. 브라우저가 탭마다 프로세스를 나누는 이유, 컨테이너가 프로세스 경계를 기본 단위로 삼는 이유가 전부 이 격리입니다. 한쪽이 크래시해도 전체가 죽으면 안 되는 상황이라면 격리 비용은 지불할 가치가 있습니다. 무거운 것과 틀린 것은 다릅니다 — 무엇을 사려고 그 값을 내는지가 중요합니다.
시뮬레이터에서 해보기
이 단원의 용어
왜 이렇게 발전했나
초창기 컴퓨터는 프로그램을 한 번에 하나만 돌렸습니다(배치 처리). 그런데 프로그램이 테이프나 디스크를 기다리는 동안 비싼 CPU가 통째로 놀았습니다. 이 낭비를 없애려고 여러 프로그램을 메모리에 함께 올려두고 번갈아 실행하는 방식이 나왔고, 서로 망가뜨리지 않게 격리하는 장치가 함께 발전했습니다.
프로세스 = 격리된 메모리 한 벌 + 실행 흐름 하나. 동시가 아니라 교대.
남은 문제
그런데 "갈아탄다"는 게 정확히 무슨 뜻일까요? 실행 중이던 프로그램은 어떻게 나중에 이어서 실행될까요? 그리고 CPU는 대체 언제 쉴까요? →