공룡책과 함께 OS를 배워보자 1일차 - Overview
본 포스트는 공룡책이라 불리는 Abraham Silberschatz, Peter B. Galvin, Greg Gagne의 『Operating System Concept 10th』 을 바탕으로 작성하였습니다.
Ch 1. Overview
1장에서는 이 책의 전반적인 내용을 모두 담고 있다. 따라서 책을 모두 읽고 난 후 다시 1장을 읽어보는 것을 추천한다.
운영체제는 컴퓨터 사용자와 컴퓨터 하드웨어 사이에서 중개자(intermediary) 역할을 한다.
운영체제의 목적은 사용자가 프로그램을 편리하고 효율적으로 수행할 수 있는 환경을 제공하는 데 있다.
1.0 Introduction
운영체제는 컴퓨터 하드웨어를 관리하는 소프트웨어이다.
또한 응용 프로그램을 위한 기반을 제공하는데, 놀라운 점은 이러한 일들을 매우 다양한 위치에서 다양한 방법으로 수행한다는 것이다.
운영체제는 "사물 인터넷(Inter-net of Things)"을 포함하는 자동차와 홈 기기에서부터, 스마트폰, PC, 클라우드 컴퓨팅 환경까지 어느 곳에나 존재한다.
따라서 현대 컴퓨팅 환경에서 운영체제의 역할을 탐구하기 위해선, 먼저 컴퓨터 하드웨어의 구성과 구조를 이해하는 것이 중요하겠다.
이러한 지식에는 CPU, 메모리 및 I/O 장치, 저장장치가 포함된다.
1.1 What Operating Systems Do
컴퓨터 시스템은 대개 네 가지 구성요소인 하드웨어, 운영체제, 응용 프로그램 및 사용자로 구분할 수 있다.
1) 하드웨어
하드웨어는 중앙 처리 장치(CPU), 메모리 및 입출력(I/O) 장치로 구성되어, 기본 계산용 자원을 제공한다.
2) 응용 프로그램
응용 프로그램이란 워드 프로세서, 스프레드시트, 컴파일러, 웹 브라우저 등을 말하며 사용자의 계산 문제를 해결하기 위해 이들 자원이 어떻게 사용될지를 정의한다.
3) 운영체제
위 구성도에서 운영체제는 다양한 사용자를 위해 다양한 응용 프로그램 간의 하드웨어 사용을 제어하고 조정하는 역할을 한다.
이런 운영체제의 모습은 정부(government)의 모습과 비슷한데, 운영체제 자체로는 유용한 기능을 수행하지 못하기 때문이다.
운영체제는 단순히 다른 프로그램이 유용한 작업을 할 수 있는 환경을 제공하는 것뿐이다.
* 사용자 관점에서의 운영체제
컴퓨터에 대한 사용자의 관점은 사용되는 인터페이스에 따라 달라진다.
1) 퍼스널 컴퓨터 (PC)
많은 컴퓨터 사용자는 모니터, 키보드, 마우스 등으로 구성된 PC 앞에서 작업을 하는데, 이러한 시스템은 한 사용자가 자원을 독점하도록 설계된 구조이다. 목표는 사용자가 수행하는 작업을 최대화하는 것이다.
이러한 경우 운영체제는 대부분 사용의 용이성을 위해 설계되며 다양한 하드웨어와 소프트웨어 자원이 어떻게 공유되느냐의 자원의 이용에는 전혀 신경 쓰지 않는다.
2) 모바일 장치
모바일 장치에서 일반적으로 사용자는 실제 키보드, 마우스를 사용하지 않고 터치스크린을 통해 사용자와 상호작용한다.
또한 최근엔 많은 사용자가 Apple의 Siri와 같은 음성 인식 인터페이스를 통해 상호 작용하게 된다.
3) 내장형 컴퓨터
가전제품이나 자동차 내의 내장형 컴퓨터는 화면을 보여주긴 하나, 이들 운영체제와 응용 프로그램은 사용자의 개입 없이 작동하도록 설계되어 있다.
* 시스템 관점에서의 운영체제
컴퓨터의 관점에서 운영체제는 하드웨어와 가장 밀접하게 연관된 프로그램이다.
따라서 우리는 운영체제를 자원 할당자(resource allocator)로 볼 수 있다.
컴퓨터 시스템은 문제를 해결하기 위해 요구되는 여러 가지 자원들 (CPU 시간, 메모리 공간, 저장 공간, 입출력 장치 등)을 가진다.
운영체제는 이들 자원의 관리자로서 동작한다.
자원에 대해 서로 상충되는 많은 요청들이 있으므로, 운영체제는 컴퓨터 시스템을 효율적이고 공정하게 운영할 수 있도록 어느 요청에 자원을 할당할지를 결정해야 한다.
* 운영체제의 정의
일반적으로 운영체제에 대한 적합한 정의는 없다. 운영체제는 유용한 컴퓨팅 시스템을 만드는 문제를 해결할 수 있는 합리적인 방법을 제공하기 때문에 존재한다.
컴퓨터 시스템의 기본 목표는 프로그램을 실행하고 사용자의 문제를 더욱 쉽게 해결할 수 있게 하는 것인데, 하드웨어만으로는 쉽지 않으므로 응용 프로그램이 개발되는 것이다.
그런데, 이러한 프로그램에는 입출력 장치 제어와 같은 특정 공통 작업이 필요하고, 이런 기능들은 운영체제라는 하나의 소프트웨어로 통합된다.
보다 일반적인 정의는, 운영체제가 컴퓨터에서 항상 실행되는 프로그램이다. (일반적으로 커널이라 한다.)
1.2 컴퓨터 시스템의 구성 (Computer-System Organization)
현대의 범용 컴퓨터 시스템은 하나 이상의 CPU와 구성요소와 공유 메모리 사이의 액세스를 제공하는 공통 버스를 통해 연결된 여러 장치 컨트롤러로 구성된다.
위 그림에서 각 장치 컨트롤러는 특정 유형의 장치 (디스크, 오디오 장치 등)를 담당한다.
장치 컨트롤러는 제어하는 주변 장치와 로컬 버퍼 저장소 간에 데이터를 이동하는 역할을 한다.
일반적으로 운영체제에는 각 장치 컨트롤러마다 장치 드라이버가 있는데, CPU와 장치 컨트롤러는 병렬로 실행되어 메모리 사이클을 놓고 경쟁한다.
* 인터럽트
하드웨어는 어느 순간이든 시스템 버스를 통해 CPU에 신호를 보내 인터럽트를 발생시킬 수 있다.
인터럽트는 다른 많은 목적으로도 사용되며 운영체제와 하드웨어의 상호 작용 방식의 핵심 부분이다.
* CPU가 인터럽트 되면 발생하는 일들
1) CPU가 인터럽트 되면,
2) CPU는 하던 일을 중단하고 즉시 고정된 위치로 실행을 옮긴다. 이러한 고정된 위치는 일반적으로 인터럽트를 위한 서비스 루틴이 위치한 시작 주소를 가지고 있다.
3) 그리고 인터럽트 서비스 루틴이 실행된다.
4) 인터럽트 서비스 루틴의 실행이 완료되면, CPU는 인터럽트 되었던 연산을 재개한다.
위 과정에 대한 타임라인은 다음 그림과 같다.
요약하자면, 인터럽트는 최신 운영체제에서 비동기 이벤트를 처리하기 위해 사용된다.
인터럽트는 시간에 민감한 처리에 빈번하게 사용되므로 시스템 성능을 좋게 하려면, 효율적인 인터럽트 처리가 필요하다.
* 저장장치 구조
CPU는 메모리에서만 명령을 적재할 수 있으므로 실행하려면 프로그램을 먼저 메모리에 적재해야 한다.
범용 컴퓨터는 프로그램 대부분을 메인 메모리(RAM)라는 재기록 가능한 메모리에서 가져온다.
컴퓨터는 다른 형태의 메모리도 사용하는데, 예를 들어 부트스트랩 프로그램은 운영체제를 적재하고 있으며 컴퓨터 전원을 켤 때 가장 먼저 실행되는 프로그램이다. 이때 RAM은 휘발성(전원이 꺼질 때 내용이 손실되는) 메모리이므로 부트스트랩 프로그램을 유지하는 용도로 사용할 수 없다.
대신 컴퓨터는 전기적으로 소거 가능한 프로그램 가능 읽기 전용 메모리(EEPROM) 및 기타 형태의 펌웨어를 사용한다.
이상적으로 생각했을 때는, 프로그램과 데이터가 메인 메모리에 영구히 존재하면 당연히 좋다.
하지만 이는 대부분의 시스템에서 두 가지 이유로 불가능하다.
- 메인 메모리는 모든 필요한 프로그램과 데이터를 영구히 저장하기에는 너무 작다.
- 메인 메모리는 이미 언급한 것처럼 전원이 공급되지 않으면 그 내용을 잃어버리는 휘발성 저장 장치이다.
따라서 대부분의 컴퓨터 시스템은 메인 메모리의 확장으로 보조저장장치를 제공한다.
보조 저장장치의 주요 요건은 대량의 데이터를 영구히 보존할 수 있어야 한다는 점이다.
가장 일반적인 보조 저장장치로는 하드 디스크 드라이브(HDD)와 비휘발성 메모리(NVM) 장치로, 프로그램과 데이터 모두를 위한 저장소를 제공한다.
이 밖에도 여러 저장장치 종류가 있는데, 보통 저장장치 간의 주된 차이점은 속도, 가격, 크기, 휘발성이다.
또한 모든 게 완벽한 저장장치는 없다. 무언가가 좋으면 다른 곳은 안 좋은, 일명 trade off 상황이 발생하기 마련이다.
1.3 컴퓨터 시스템 구조 (Computer-System Architecture)
앞 절에서는 전형적인 컴퓨터 시스템의 일반적인 구조를 소개하였다. 컴퓨터 시스템은 사용된 범용 처리기의 수에 따라 분류 가능한 다양한 방식으로 구성될 수 있다.
* 단일 처리기 시스템
몇 년 전까지만 해도, 대부분의 컴퓨터 시스템은 단일 처리 코어를 가진 하나의 CPU를 포함하는 단일 프로세서를 사용했다.
코어는 명령을 실행하고 로컬로 데이터를 저장하기 위한 레지스터를 포함하는 구성 요소이다.
코어를 가진 하나의 메인 CPU는 프로세스의 명령어를 포함하여 범용 명령어 세트를 실행할 수 있다.
* 다중 처리기 시스템
최신 컴퓨터에서는 다중 처리기 시스템이 컴퓨팅 환경을 지배하고 있다.
일반적으로 이러한 시스템에는 각각 단일 코어 CPU가 있는 두 개 이상의 프로세서가 있다.
다중 처리기 시스템의 주요 장점은 처리량 증가이다. 즉, 프로세서 수를 늘리면 더 적은 시간에 더 많은 작업을 수행할 수 있다.
다만 N개의 프로세서가 있다고 N배의 효율이 증가하지는 않는데,
그 이유는 여러 프로세서가 하나의 작업에 협력할 때 모든 프로세서가 올바르게 작동하게 유지하는 데 일정한 양의 오버헤드가 발생하기 때문이다. 이를 경합이라 한다.
* 컴퓨터 시스템 구성요소의 정의
- CPU - 명령을 실행하는 하드웨어
- 프로세서(processor) - 하나 이상의 CPU를 포함하는 물리적 칩
- 코어(core) - CPU의 기본 계산 단위
- 다중 코어(multicore) - 동일한 CPU에 여러 컴퓨팅 코어를 포함함
- 다중 처리기(multiprocessor) - 여러 프로세서를 포함함
사실상 거의 모든 시스템은 이제 다중 코어이지만, 컴퓨터 시스템의 단일 계산 단위를 가리킬 때는 일반적 용어인 CPU를 사용하고
하나의 CPU에 존재하는 하나 이상의 코어를 구체적으로 언급할 때 코어와 다중 코어 용어를 사용한다.
1.4 운영체제의 작동 (Operating-System Operations)
이 장에서는 많은 운영체제의 공통적인 특징에 대해 논의한다.
* 멀티프로그래밍과 멀티태스킹
운영체제의 가장 중요한 측면 중 하나는 하나의 프로그램은 항상 CPU나 I/O 장치를 바쁘게 유지할 수 없으므로 여러 프로그램을 실행할 수 있다는 것이다. (한 프로그램이 모든 장치를 사용해 동작하지 않는다는 의미)
또한 사용자는 일반적으로 한 번에 둘 이상의 프로그램을 실행하려 한다.
멀티프로그래밍은 CPU가 항상 한 개는 실행할 수 있도록 프로그램을 구성하여 CPU 이용률을 높이고 사용자 만족도를 높인다.
이런 시스템에서 실행 중인 프로그램을 프로세스라고 한다.
멀티태스킹은 멀티프로그래밍의 논리적 확장이다. 멀티태스킹 시스템에서 CPU는 여러 프로세스를 전환하며 프로세스를 실행하지만 전환이 자주 발생하여 사용자에게 빠른 응답 시간을 제공하게 된다.
보통 사람이 사용하는 마우스, 키보드를 통한 출력은 사람의 속도로 수행되므로, 완료 시까지 상당히 긴 시간이 걸릴 수 있다.
예를 들어 사람에게 1초에 7 문자를 타이핑하는 것은 빠른 편이지만, 컴퓨터에게는 아주 느린 것이다.
이러한 대화식 입력이 진행되는 동안 CPU를 쉬게 하지 않고, 운영체제는 CPU를 다른 사용자의 프로그램으로 신속하게 전환한다.
* 이중 모드와 다중모드 운용
운영체제와 사용자는 컴퓨터 시스템의 하드웨어 및 소프트웨어 자원을 공유하기 때문에 올바르게 설계된 운영체제는 잘못된 (또는 악의적인) 프로그램으로 인해 다른 프로그램 또는 운영체제 자체가 잘못 실행될 수 없도록 보장해야 한다.
따라서 시스템을 올바르게 실행하려면 운영체제 코드 실행과 사용자 정의 코드 실행을 구분할 수 있어야 한다.
이는 적어도 두 개의 독립된 연산 모드, 즉 사용자 모드와 커널 모드(supervisor mode, system mode, privileged mode)를 필요로 한다. 모드 비트라고 하는 하나의 비트가 현재의 모드를 나타내기 위해 컴퓨터의 하드웨어에 추가되었다. 이 비트는 커널 모드(0) 또는 사용자 모드(1)를 나타낸다.
시스템 부트 시, 하드웨어는 커널 모드에서 시작한다. 이어 운영체제가 적재되고, 사용자 모드에서 사용자 프로세스가 시작된다.
트랩이나 인터럽트가 발생할 때마다, 하드웨어는 사용자 모드에서 커널 모드로 전환한다.(모드 비트를 0으로 변경)
그러므로 운영체제가 컴퓨터의 제어를 얻을 때마다 항상 커널 모드에 있게 된다.
1.5 자원 관리 (Resource Management)
앞서 본 것처럼 운영체제는 자원 관리자이다. 시스템의 CPU, 메모리 공간, 파일-저장 공간 및 I/O 장치는 운영체제가 관리해야 하는 자원에 속한다.
* 프로세스 관리
프로그램은 CPU에 의해 명령이 실행되지 않으면 아무것도 할 수 없다. 이전에 언급했듯 실행 중인 프로그램은 프로세스이다.
프로세스는 자기 일을 수행하기 위해 CPU 시간, 메모리, 파일, 그리고 입출력 장치를 포함한 여러 가지 자원을 필요로 한다.
프로그램은 수동적(passive) 개체인 반면, 프로세스는 능동적(active)인 개체이다.
한 프로세스의 수행은 반드시 순차적이어야 한다. 따라서 두 개의 프로세스가 동일한 프로그램과 연관되어 있더라도, 그들은 두 개의 별도의 수행 순서로 간주된다.
다중 스레드 프로세스는 여러 개의 프로그램 카운터를 가지고 있으며 이 카운터들은 각 스레드가 실행할 다음 명령어를 가리키게 된다.
한 프로세스는 한 시스템 내의 작업의 단위이다. 이러한 시스템은 프로세스의 집합으로 구성되는데, 프로세스들 중 일부는 운영체제 프로세스들(시스템 코드 수행)이며, 나머지는 사용자 프로세스들(사용자 코드 수행)이다.
운영체제는 프로세스 관리와 연관해 다음과 같은 활동에 대한 책임을 진다.
- CPU에 Process와 thread를 Schedule 하기.
- User Process와 System Process의 생성과 제거
- Process의 일시 중지와 재수행
- Process Synchronization를 위한 기법 제공
- Process Communication을 위한 기법 제공
* 메모리 관리
메인 메모리는 현대 컴퓨터 시스템의 작동에 중추적인 역할을 한다.
메인 메모리의 특징
- 메인 메모리는 CPU와 입출력 장치에 의해 공유되는, 빠른 접근이 가능한 데이터의 저장소이다.
- 일반적으로 CPU가 직접 주소를 지정할 수 있고, 직접 접근할 수 있는 유일한 대량 메모리이다.
프로그램이 수행되기 위해서는 반드시 절대 주소로 매핑(mapping)되고 메모리에 적재되어야 한다.
프로그램을 수행하면서, 이러한 절대 주소를 생성하여 메모리의 프로그램 명령어와 데이터에 접근한다.
결국, 프로그램이 종료되고, 프로그램이 차지하던 메모리 공간은 가용 공간으로 선언되고, 다음 프로그램이 적재되어 수행될 수 있다.
운영체제는 CPU 이용률과 사용자에 대한 컴퓨터의 응답 속도를 개선하기 위해, 메모리에 여러 개의 프로그램을 유지해야 하며 이를 위해서 메모리 관리 기법이 필요하다. 따라서 운영체제는 메모리 관리와 관련하여 다음과 같은 일을 담당해야 한다.
- 메모리의 어느 부분이 현재 사용되고 있으며 어느 프로세스에 의해 사용되고 있는지를 추적해야 한다.
- 필요에 따라 메모리 공간을 할당하고 회수해야 한다.
- 어떤 프로세스들을 메모리에 적재하고 제거할 것인가를 결정해야 한다.
* 캐시 관리
캐싱은 컴퓨터 시스템의 중요한 원리이다.
정보는 통상 어떤 저장장치에 보관되는데, 정보가 사용됨에 따라 더 빠른 장치인 캐시에 일시적으로 복사될 수 있다.
그러므로 우리는 특정 정보가 필요할 경우, 먼저 캐시에 그 정보가 있는지를 조사해 보아야 한다.
CPU 내부의 프로그램 가능한 레지스터들은 메인 메모리를 위한 고속의 캐시로 볼 수 있다.
또 전적으로 하드웨어로 구현된 캐시도 있다. 시스템 대부분은 다음에 수행될 것으로 예상되는 명령을 넣어 두는 명령 캐시를 가지고 있다.
하지만 이 책에서 하드웨어만으로 구성된 캐시는 운영체제로 제어 불가능하기 때문에 다루지 않을 예정이다.
캐시는 크기가 제한되어 있기 때문에 캐시 관리는 중요한 설계 문제이다.
캐시 크기와 교체 정책을 신중하게 선택하면 성능이 크게 향상될 수 있다.
저장장치의 계층 구조에서 각 수준 간의 정보 이동은 하드웨어 설계나 제어하는 운영체제에 따라 명시적, 또는 묵시적으로 이루어진다.
예를 들어, 캐시 -> CPU or 레지스터로의 데이터 전송은 통상 운영체제의 간섭 없이 하드웨어적으로 이루어진다.
반면 디스크와 메모리 간 데이터 전송은 통상 운영체제에 의해 제어된다.
위 그림과 같이 단순한 단일 처리기 환경에서는 캐시 값에 오류가 생길 문제가 없다.
그러나 CPU가 여러 개의 프로세스 사이에서 이리저리 전환되는 멀티태스킹 환경에서는, 여러 개의 프로세스가 같은 데이터에 접근하기를 원할 경우, 가장 최근에 갱신된 데이터 값을 얻는 것을 보장하기 위해 주의가 필요하다.
예를 들어, A의 복사본이 동시에 여러 캐시에 존재한다고 가정한다. 이때, 여러 개의 CPU가 모두 동시에 실행되는 경우, 한 캐시에 있는 A 값이 갱신될 경우 그것이 A가 존재하는 모든 캐시에 즉각적으로 반영되어야 한다. 이러한 상황을 캐시 일관성(Cache Coherency) 문제라고 하며, 이는 일반적으로 하드웨어적 문제이다.