콘텐츠로 이동

01. OS introduction

가장 중점으로 볼 세가지:
가상화 (virtualization), 병행성(concurrency), 영속성 (persistence)

OS Introduction

https://pages.cs.wisc.edu/~remzi/OSTEP/Korean/02-intro.pdf

운영체제 개요

  • 프로그램이 실행될 때 일어나는 일
  1. fetch (반입)
  2. decode (해석) 무슨 명령어인지 파악
  3. execute 실행

스크린샷 2022-10-26 오전 11.14.24.png
스크린샷 2022-10-26 오전 11.14.42.png

운영체제는 CPU, 메모리, 디스크와 같은 물리 자원을 가상화(virtualize)한다.
운영체제는 병행성과 관련된 복잡한 문제를 처리한다.
파일을 영속적으로 저장하여 아주 오랜 시간 동안 안전한 상태에 있게 한다.

CPU 가상화 (Virtualization)

핵심 질문: 자원을 어떻게 가상화시키는가

  • 가상화 효과를 얻기 위하여 운영체제가 구현하는 기법과 정책은 무엇인가?
  • 운영체제는 이들을 어떻게 효율적으로 구현하는가?
  • 어떤 하드웨어 지원이 필요한가?

하나의 CPU 또는 소규모 CPU 집합을 무한개의 CPU가 존재하는 것처럼 변환하여 동시에 많은 수의 프로그램을 실행시키는 것을 CPU 가상화(virtualizing the CPU) 라고 한다.

Operating System is responsible for allocating seperate of their space for each process.
다수의 프로그램을 동시에 실행시키는 기능에서 동시성 문제가 발생함.
예를 들어, 특정 순간에 두 개의 프로그램이 실행되기를 원한다면, 누가 실행되어야 하는가?
→ 운영체제 정책에 달려있음.

이때 자원 관리자로서의 운영체제 역할을 보아야함.

스크린샷 2022-10-26 오전 11.34.45.png

스크린샷 2022-10-26 오전 11.42.35.png
우선 메모리를 할당받는다 (a1 행).
그런 후 할당받은 메모리의 주소를 출력한다 (a2).
새로 할당받은 메모리의 첫 슬롯에 숫자 0 을 넣는다 (a3).
마지막으로 루프로 진입하여 1초 대기 후, 변수 p가 가리키는 주소에 저장되어 있는 값을 1 증가시킨다.
출력할 때마다 실행 중인 프로그램의 프로세스 식별자 (PID)라 불리는 값이 함께 출력된다.

스크린샷 2022-10-26 오전 11.43.19.png

같은 프로그램을 여러 번 실행시켜 보자 (그림 5.4). 프로그램들은 같은 주소에 메모리를 할당받지만 (00200000), 각각이 독립적으로 00200000 번지의 값을 갱신한다.
각 프로그램은 물리 메모리를 다른 프로그램과 공유하는 것이 아니라 각자 자신의 메모리를 가지고 있는 것처럼 보인다.

운영체제가 메모리 가상화(virtualizing memory)를 하기 때문에 이런 현상이 생긴다. 각 프로세스는 자신만의 가상 주소 공간(virtual address space, 때로 그냥 주소 공간(address space)이라고 불림)을 갖는다.
운영체제는 이 가상 주소 공간을 컴퓨터의 물리 메모리로 매핑 (mapping)한다.
하나의 프로그램이 수행하는 각종 메모리 연산은 다른 프로그램의 주소 공간에 영향을 주지 않는다. 실행 중인 프로그램의 입장에서는, 자기 자신만의 물리 메모리를 쓰는 셈이다. 실제로는 물리 메모리는 공유 자원이고, 운영체제에 의해 관리된다.
이러한 일들이 정확히 어떻게 일어나는지 역시 이 책의 첫 주제 가상화(virtualization)에 포함된다.

병행성 (Concurrency)

핵심 질문 : 올바르게 동작하는 병행 프로그램은 어떻게 작성해야 하는가

  • 같은 메모리 공간에 다수의 쓰레드가 동시에 실행한다고 할 때, 올바르게 동작하는 프로그램을 어떻게 작성할 수 있는가?
  • 운영체제로부터 어떤 기본 기법들을 제공받아야 하는가?
  • 하드웨어는 어떤 기능을 제공해야 하는가?
  • 병행성 문제를 해결하기 위하여 기본 기법들과 하드웨어 기능을 어떻게 이용할 수 있는가?

프로그램이 한 번에 많은 일을 하려 할 때 (즉, 동시에) 발생하는 그리고 반드시 해결해야 하는 문제들을 가리킬 때 이 용어를 사용한다.
병행성 문제는 우선 운영체제 자체에서 발생한다. 가상화에 관한 앞의 예에서 알 수 있듯이 운영체제는 한 프로세스 실행, 다음 프로세스, 또 다음 프로세스 등의 순서로 여러 프로세스를 실행시켜 한 번에 많은 일을 한다. 이때 문제가 발생한다.
(병행성 문제는 운영체제만의 문제는 아니다. 멀티 쓰레드 프로그램도 동일한 문제를
드러낸다.)

다음 코드를 살펴보자.

스크린샷 2022-11-03 오전 9.52.05.png

메인 프로그램은 Pthread_create()를 사용하여 두 개의 쓰레드를 생성한다.
쓰레드를 동일한 메모리 공간에서 함께 실행 중인 여러 개의 함수라고 생각할 수 있다.
이 예제 코드에서 각 쓰레드는worker()라는 루틴을 실행한다.
worker() 루틴은 loops번 만큼 루프를 반복하면서 카운터 값을 증가시킨다.

loops 변수를 1000으로 설정하여 프로그램을 실행시켰을 때 어떤 일이 일어나는지
아래에 나와 있다. loops 값은 각 쓰레드가 카운터를 증가시키는 횟수다. loops 값을
1000으로 지정한 후 프로그램을 실행시키면, counter 변수의 최종 값은 얼마가 될까?

각 쓰레드가 1000번씩 counter 값을 증가시켰기 때문에 counter의 최종
값은 2000이 된다.
직관적으로 생각하면 사실 loops 값이 N 이면 프로그램의 최종 출력은 2N 이 되리라고
예상할 수 있다. 그러나 실제로는 그렇지 않다.

스크린샷 2022-11-03 오전 10.12.24.png
앞 프로그램의 핵심 부분인 counter를 증가시키는 부분은 세 발의 명령어로 이루어진다.

  1. counter 값을 메모리에서 레지스터로 탑재하는 명령어
  2. 레지스터를 1 증가시키는 명령어
  3. 레지스터의 값을 다시 메모리에 저장하는 명령어
    이렇게 3번의 명령어로 구성된다. 이 세 번의 명령어가 원자적(atomically)으로 (한 번에 3번 모두)
    실행되지 않기 때문에 이상한 일이 발생할 수 있다.

후반부에서 자세하게 살펴볼 것이라서 현상만 살펴보고 스킵함

영속성 (persistence)

핵심 질문 : 데이터를 영속적으로 저장하는 방법은 무엇인가

  • 파일 시스템은 데이터를 영속적으로 관리하는 운영체제의 일부분이다. 올바르게 일하기 위해서는 어떤 기법이 필요할까?
  • 이러한 작업의 성능을 높이기 위해서 어떤 기법과 정책이 필요한가?
  • 하드웨어와 소프트웨어가 실패하더라도 올바르게 동작하려면 어떻게 해야 하는가?

스크린샷 2022-11-03 오전 10.12.50.png

CPU나 메모리 가상화와는 달리 운영체제는 프로그램 별로 가상 디스크를 따로
생성하지 않는다. 오히려 사용자들이 종종 파일 정보를 공유하기 원한다고 가정한다.

다음 코드를 살펴보자.
문자열 “hello world”를 포함한 파일 /tmp/file을 생성하는 코드이다.
스크린샷 2022-11-03 오전 10.17.01.png

여기서 프로그램은 운영체제를 세 번 호출한다. 1.open() 콜은 파일을 생성하고 연다. 2. write() 콜은 파일에 데이터를 쓴다. 3. close() 콜은 단순히 파일을 닫는데, 프로그램이 더 이상 해당 파일을 사용하지 않는다는 것을 나타낸다.
그러고 이들 시스템 콜 (system call)은 운영체제에서 파일 시스템(file system)이라 불리는 부분으로 전달된다.
파일 시스템은 많은 작업을 해야 한다. 먼저 새 데이터가 디스크의 어디에 저장될지 결정해야 하고, 파일 시스템이 관리하는 다양한 자료 구조를 통하여 데이터의 상태를 추적해야 한다. 이런 작업을 하기 위해서는 저장 장치로부터, 기존 자료 구조를 읽거나 갱신해야 한다.

성능향상을 위해서 대부분의 파일 시스템은 쓰기요청을 지연시켜 취합된 요청들을 한 번에 처리한다. 쓰기 중에 시스템의 갑작스런 고장에 대비해서 많은 파일 시스템들이 저널링(journaling) 이나 쓰기-시-복사(Copy-On-Write) 와 같은 복잡한 쓰기 기법을 사용한다.

이런 기법들은 쓰기 순서를 적절히 조정하여 고장이 발생하더라도 정상적인 상태로 복구될 수 있게 한다. 효율적인 디스크 작업을 위해 단순 리스트에서 복잡한 B-트리까지 다양한 종류의 자료 구조를 사용한다.

이후 영속성을 다루는 파트에서 장치와 입출력에 관한 전반적인 내용과 디스크, RAID와 파일 시스템에 대해 매우 상세하게 다룰 것임

설계 목표

정리
운영체제는 CPU, 메모리, 디스크와 같은 물리 자원을 가상화(virtualize)한다.
운영체제는 병행성과 관련된 복잡한 문제를 처리한다.
파일을 영속적으로 저장하여 아주 오랜 시간 동안 안전한 상태에 있게 한다.

  • 가장 기본적인 목표: 추상화
    가장 기본적인 목표는 시스템을 편리하고 사용하기 쉽게 만드는 데 필요한 개념(abstraction)들을 정의하는 것

  • 가장 중요한 목표: 성능
    운영체제의 설계와 구현에 중요한 목표는 성능이다.
    다른 말로 표현하면 오버헤드를 최소화(minimize the overhead)하는 것

  • 보호
    응용 프로그램 간의 보호, 그리고 운영체제와 응용 프로그램 간의 보호이다. 다수 프로그램들이 동시에 실행되기 때문에, 운영체제는 한 프로그램의 악의적인 또는 의도치 않은 행위가 다른 프로그램에게 피해를 주지 않는다는 것을 보장해야 한다. 보호는 운영체제의 원칙 중 하나인 고립(isolation) 원칙의 핵심이다. 프로세스를 다른 프로세스로부터 고립시키는
    일은 보호의 핵심이고 운영체제가 해야 하는 일 중 많은 부분의 근간이 된다.

  • 높은 신뢰성
    운영체제는 계속 실행되어야 한다. 운영체제가 실패하면 그 위에서 실행되는 모든
    응용 프로그램도 실패하게 된다. 이러한 종속성 때문에 운영체제는 높은 수준의 신뢰성(reliability)을 제공해야 한다.

  • 그 외 목표

  1. 에너지-효율성(energy-eiciency)
  2. 악의적인 응용 프로그램에 대한 보안(security, 사실은 보호의 확장)
  3. 이동성(mobility): 운영체제가 작은 장치에서 사용될수록 중요함


마지막 업데이트 : 2025년 4월 23일
작성일 : 2023년 4월 2일