본문으로 이동
  • 현재 모든 문서는 작성 중입니다. 보시는 데 불편함이 있더라도 양해 부탁드립니다.

운영체제 기본/서문

~ldmsys

음악을 들으면서 큰 파일을 복사하고, 문서 편집기에 글을 쓰고 있다고 하자. 복사는 한동안 계속되지만 그동안 음악이 끊기거나 입력한 글자가 한참 뒤에 나타나기를 바라지는 않는다. 세 프로그램은 모두 CPU와 메모리, 장치를 사용한다. 한 프로그램이 먼저 실행되었다는 이유로 이 자원을 끝까지 독차지하게 둘 수는 없다.

운영체제(Operating System, OS)는 이런 프로그램들이 함께 실행될 환경을 마련한다. 누구에게 어떤 자원을 얼마나 줄지 결정한다는 점에서는 자원 관리자(Resource Allocator), 프로그램의 실행을 관리하고 잘못된 사용이 다른 작업까지 망가뜨리지 않도록 한다는 점에서는 제어 프로그램(Control Program)이다. 파일 복사를 계속 진행하면서 편집기에 실행 기회를 주는 일과, 오작동한 프로그램이 편집 중인 문서를 메모리에서 덮어쓰지 못하게 하는 일은 이 두 역할의 예다.[1]

자원 배분

복사 프로그램이 저장장치에서 데이터를 읽어 오기를 기다리는 동안에는 CPU로 할 일이 없을 수 있다. 이때 CPU까지 함께 쉬게 할 필요는 없다. 운영체제는 실행할 준비가 된 편집기나 음악 재생기에 CPU를 배정할 수 있다. 나중에 복사 프로그램으로 돌아오려면 어느 명령까지 실행했는지, 어떤 값을 계산 중이었는지를 보관해야 한다. 그래서 실행 중인 프로그램의 자원과 상태를 묶는 프로세스, 그 안에서 명령을 실행하는 흐름인 스레드가 필요하다. 프로세스와 스레드에서는 이 상태를 어떻게 나누고 실행을 어떻게 이어 가는지 다룬다.

누구를 먼저 실행할지도 문제다. 복사를 빨리 끝내는 것만 목표로 삼으면 다른 작업의 반응이 늦어질 수 있고, 입력에 자주 반응하려면 하던 작업을 중단하고 다시 이어야 한다. 자원을 낭비하지 않는 효율, 특정 작업이 계속 밀리지 않게 하는 공정성, 요청에 빠르게 반응하는 응답성을 함께 고려해야 한다. 스케줄링은 이런 기준에 따라 실행 순서를 정하는 일이다. 모든 작업에 같은 시간을 주는 것이 언제나 좋은 배분은 아니며, 운영체제가 있다고 해서 과부하 상태에서도 음악이 반드시 끊기지 않는 것은 아니다.[1]

메모리는 시간을 나누는 것만으로 해결되지 않는다. 편집 중인 문서와 재생할 음악 데이터, 복사 중인 데이터가 함께 들어갈 공간이 필요하다. 프로그램을 열고 닫다 보면 빈 공간도 여기저기 흩어진다. 프로그램이 이런 물리적 배치를 직접 계산하게 하는 대신, 각 프로그램이 사용하는 주소와 실제 메모리 위치를 분리할 수 있다. 가상 메모리는 이 연결을 관리하며 배치·보호·공유를 다루는 방법이다. 프로그램에는 연속된 배열처럼 보여도 실제 RAM에서는 여러 조각에 나누어 둘 수 있다. 물론 이 방법이 RAM의 총량을 무한하게 만들어 주지는 않는다.[2]

프로그램 실행의 제어

복사 프로그램이 버그 때문에 끝없는 계산에 빠졌다고 하자. 그 프로그램이 스스로 CPU를 양보하기만 기다린다면 편집기에 실행 기회를 줄 수 없다. 운영체제가 다시 제어를 얻을 수단이 필요하다. 타이머가 일정 시간이 지났음을 알리는 인터럽트는 현재 실행 중인 코드에서 운영체제로 제어를 넘기는 계기가 된다. 저장장치도 데이터 전송이 끝났음을 인터럽트로 알릴 수 있다. 운영체제는 그 통지를 처리하고 기다리던 작업을 다시 실행할 수 있게 한다. 장치 제어와 입출력에서는 장치에 일을 시키고, 데이터를 옮기고, 완료를 확인하는 과정을 구분한다.[3]

잘못된 포인터로 편집기의 메모리를 덮어쓰는 문제는 실행 순서를 바꾸는 것만으로 막을 수 없다. 운영체제는 프로그램마다 접근할 수 있는 메모리와 직접 실행할 수 있는 동작의 범위를 정한다. 다만 모든 메모리 접근을 운영체제 코드가 일일이 검사할 수는 없다. CPU의 권한 모드와 메모리 접근 검사 같은 하드웨어의 도움으로 그 경계를 강제한다. 이것이 보호가 필요한 이유다. 운영체제가 복사할 내용을 올바르게 골랐는지까지 판단하는 것이 아니라, 잘못된 프로그램이 허용된 범위 밖을 건드리지 못하게 하는 것이다.[4]

반대로 프로그램끼리 협력해야 할 때도 있다. 한 프로그램이 압축을 풀고 다른 프로그램이 그 결과에서 문자열을 찾는다면, 서로의 메모리를 마음대로 읽게 하지 않고도 데이터를 전달할 길이 필요하다. 운영체제는 파이프처럼 데이터를 건네는 통로나, 명시적으로 함께 쓰는 메모리 영역을 제공한다. 프로세스 간 통신은 격리를 유지하면서 필요한 교류를 가능하게 하는 방법을 다룬다.[4]

공유를 허용하면 순서 문제도 생긴다. 음악 재생기에서 한 스레드가 재생할 데이터를 채우고 다른 스레드가 가져간다고 하자. 아직 다 채우지 않은 데이터를 읽거나, 재생이 끝나기 전에 같은 공간을 덮어쓰면 안 된다. 운영체제 내부의 작업 대기열도 여러 실행 흐름이 함께 수정할 수 있다. 동시성에서 다루는 뮤텍스와 세마포어 같은 동기화 수단은 이러한 접근 순서를 맞추기 위해 필요하다. 운영체제가 실행 순서를 정해 준다고 해서 프로그램의 공유 데이터까지 저절로 올바르게 관리되는 것은 아니다.[5]

운영 자동화와 자원 공유

오늘날에는 여러 프로그램을 함께 쓰는 일이 자연스럽지만, 초기 대형 컴퓨터에서는 프로그램 하나를 실행하는 일에도 사람의 손이 많이 갔다. 사용자가 예약한 시간에 제어 콘솔을 조작하고 프로그램과 데이터를 넣은 뒤 결과를 회수했다. 한 사람의 계산이 끝나도 다음 사람이 실행 준비를 마칠 때까지 기계는 기다렸다. 계산할 일은 밀려 있는데 비싼 컴퓨터가 쉬는 셈이다. 이 공백을 줄이기 위해 작업의 시작과 종료를 관리하는 모니터(Monitor)와 준비된 작업들을 차례로 실행하는 일괄 처리(Batch Processing)가 발전했다. GM-NAA I/O 같은 초기 시스템은 한 작업이 실패해도 진단 정보를 남기고 다음 작업으로 넘어가도록 실행을 자동화했다.[6]

작업을 자동으로 이어 붙여도 다른 기다림이 남았다. 실행 중인 프로그램이 저장장치에서 데이터를 받는 동안 CPU가 놀 수 있었다. 다중 프로그래밍(Multiprogramming)은 이때 다른 준비된 프로그램을 실행하는 방식으로 CPU 이용률을 높였다. 앞서 파일 복사가 입출력을 기다리는 동안 편집기를 실행하는 것과 같은 생각이다. 대신 여러 프로그램을 메모리에 함께 두고, 각자의 실행 상태와 배치를 관리해야 했다. 자원을 더 잘 활용하려는 요구가 프로세스 관리와 메모리 관리의 필요성으로 이어진 것이다.[7]

컴퓨터를 쉬지 않고 돌리는 것과 사람이 편하게 사용하는 것도 같지는 않았다. 프로그램을 제출한 뒤 결과를 받아서야 작은 오류를 발견했다면, 수정한 작업을 다시 제출하고 또 기다려야 했다. 시분할(Time Sharing)은 여러 사용자가 단말에서 명령을 내리고 응답을 받도록 CPU 시간을 나누었다. 한 사용자의 긴 계산이 끝나기 전에도 다른 사용자는 작업을 진행할 수 있었다. 초기 시분할 시스템인 CTSS(Compatible Time-Sharing System)는 기계의 처리량뿐 아니라 프로그램을 수정하고 결과를 확인하는 사람의 대기 시간을 줄이는 데도 목적을 두었다. 오늘날 스케줄링에서 처리량과 응답성을 함께 고려하는 이유와 맞닿아 있다.[8]

공통 서비스와 추상화

문서 편집기에서 저장을 누를 때마다 프로그램이 저장장치의 빈 구역을 직접 찾아야 한다면 어떨까. 복사 프로그램도 같은 구역이 비어 있다고 판단하면 서로의 데이터를 덮어쓸 수 있다. 운영체제의 파일시스템은 저장 공간의 사용 상태를 관리하고, 프로그램에는 이름으로 찾고 읽고 쓸 수 있는 파일을 제공한다. 편집기는 문서 내용을 전달하고, 파일시스템은 그 내용을 어디에 보관하고 어떻게 다시 찾을지 관리한다. 파일과 입출력은 이처럼 지속적으로 보관할 데이터와 장치 사이의 연결을 다룬다.

이 공통 서비스는 프로그램을 작성하는 부담도 줄인다. 편집기는 저장 대상이 다른 장치로 바뀌었다고 해서 장치 제어 코드를 처음부터 다시 작성하지 않아도 된다. 파일을 열고 읽고 쓰는 인터페이스를 사용하고, 장치별 차이는 운영체제의 해당 계층이 처리한다. 실제 자원의 복잡한 동작을 프로그램이 사용할 대상과 연산으로 나타내는 것이 추상화다. 추상화는 운영체제의 목적 전부가 아니라, 자원 배분과 실행 제어를 하면서 사용하기 쉬운 환경을 제공하는 설계 방법이다. 다음 장인 추상화에서는 DOS의 장치 설정 사례로 이 필요성을 더 구체적으로 살펴본다.

이후의 총론은 여기서 만난 문제들을 하나씩 풀어 간다. 읽을 때는 무엇을 할지 정하는 정책과 그 결정을 실행하는 메커니즘도 구별할 필요가 있다. 편집기를 먼저 실행할지 정하는 기준은 정책이고, 복사 프로그램의 실행 상태를 보관한 뒤 편집기를 이어서 실행하는 수단은 메커니즘이다. 총론은 이런 문제와 설계상의 선택을 설명하고, Linux 각론은 실제 구현을 추적한다.

관련 문서

참고 문헌

  1. ↑ 1.0 1.1 Abraham Silberschatz·Peter B. Galvin·Greg Gagne, Operating System Concepts, 9th Edition, Chapter 1: Introduction, 슬라이드 1.4–1.8. 운영체제의 목적, 자원 관리자와 제어 프로그램의 역할.
  2. ↑ MIT PDOS, xv6: Page tables, 주소 공간과 물리 메모리의 연결.
  3. ↑ MIT PDOS, xv6: Interrupts and device drivers, 장치 완료 통지와 §6.4 타이머 인터럽트.
  4. ↑ 4.0 4.1 MIT PDOS, xv6: Operating system organization, §2.1. 자원 공유, 격리, 상호작용과 물리 자원의 추상화.
  5. ↑ MIT PDOS, xv6: Locking, 공유 자료구조와 실행 순서에 따른 오류, 상호 배제.
  6. ↑ Robert L. Patrick, Operating Systems at Conception (2008). GM-NAA I/O 설계 참여자의 초기 작업 운영과 일괄 처리에 대한 회고.
  7. ↑ Jerome H. Saltzer·John W. Gintell, The Instrumentation of Multics (1970), “Special Instrumentation for Multiprogrammed Demand Paging”. 입출력 대기와 CPU 이용률, 여러 프로그램을 유지하는 메모리 비용.
  8. ↑ MIT Computation Center, The Compatible Time-Sharing System: A Programmer's Guide (1963), 1장. 시분할의 동기와 감독 프로그램에 의한 실행 관리.