1.7 OS는 하드웨어를 관리한다

Layer view of a computer system
Application Programs
Operating System
Processor | Main Memory | I/O Device

소프트웨어(Application Programs) 가 하드웨어(Processor, Main Memory, I/O Device) 를 이용하기 위해서는 OS 를 반드시 거쳐야 한다.

  • 하드웨어에 대한 접근을 제한하기 때문에, 잘못된 하드웨어 사용을 막을 수 있다.
  • Application Programs 에서 간단하고 일관된 방법으로 하드웨어를 사용하게 할 수 있다.

위의 목적을 이루기 위해, 아래와 같은 추상화가 이루어진다.
PARA/Project/CS_APP_organize/chapter1/imgs/abstractions_provided_by_os.png

즉, files 는 I/O devices 의 추상화이고,
Virtual Memory 는 Main Memory, I/O devices 의 추상화,
Processes 는 Processor, Main Memory, I/O devices 의 추상화이다.

1.7.1 Processes

현대의 OS는 프로그램에 대해 다음과 같은 환상 을 준다.

  • 프로세서(CPU), 메인 메모리, I/O device 에 대한 독자적인 이용하는 것처럼 보인다.
  • 프로세서가 단 하나의 프로그램의 순서를 철저히 지키는 것처럼 보인다. 간섭없이
  • 해당 프로그램의 코드와 관련 데이터가 현재 메모리에 있는 유일한 정보인 것처럼 보인다.

"프로세서" 라는 개념을 통해 위와 같은 착각을 일으킬 수 있었다.
즉, "프로세서" 와 "프로그램" 은 다른 개념이다.

프로세스는 서로 배타적으로 하드웨어를 이용하면서, 동시에 여러개의 프로세스가 작동하는 것처럼
"보인다." "동시에" 라는 의미는 사실 한 프로세스의 명령어가 다른 프로세스의 명령어들 사이에 끼어들어서 작동하는 것으로 구현된다.
실제로, 보통 프로세스는 CPU의 개수보다 많이 돌아간다.

위의 "동시에" 작동하는 것처럼 보이기 위해 사용하는 각 프로세스간의 명령어 간 움직임은
라고 알려진 메카니즘에 의해 동작한다.

멀티프로세서() 는 물리적으로 여러 프로그램을 동시에 돌릴 수 있지만,
남은 논의에서는 일단 배제한다.(1.9.2 절에서 다시 언급된다.)

OS는 을 위해, 의 상태 정보를 수집하고, 추적한다.
이 상태정보를 라고 부른다.
이 상태 정보에는 PC(), 레지스터 파일, 메인 메모리의 내용 등이 있다.



여러 프로세스를 동시에 작동시키기 위해,
프로세스에서 필요한 다음 명령어 사이사이에 다른 프로세스의 명령어를 실행한다.
이 때 온전한 실행을 위해, 프로세스의 상태 정보를 수집, 추적하는데, 이를 라고 한다.

해당 내용을 hello 프로그램 실행에 적용해보자.
처음에는 shell 프로세스가 동작중이다. ./hello 를 통해 실행시키면,
./hello 에 대한 프로세스가 생성되며 해당 프로세스가 종료되면 다시 shell 프로세스로 돌아온다.

프로세스 간의 전환은 이 담당하게 된다.
은 OS 코드의 일부로 항상 메모리 위에 존재한다.

프로세스가 OS에게 특정한 요청을 할 때는 에게 제어를 넘기는 라는 특수한 함수를 호출한다.

은 분리된 프로세스가 아닌, 시스템이 프로세스를 제어하기 위해 사용하는 코드와 자료 구조의 모음이다.



시스템이 프로세스를 제어하기 위해 사용하는 코드와 자료구조의 모음.
프로세스가 아닌 운영체제의 일부이다.
프로세스는 을 통해 운영체제를 거쳐 하드웨어 자원을 이용하게 된다.

는 컴퓨터과학 분야 뿐만 아니라 개발에서도 종종 보인다.
JS: 실행 컨텍스트, golang: context 패키지
JS에서는 실행 엔진이 코드를 실행하기 위해 필요하며, golang 은 다른 고루틴에게 정보 전달용이다.
즉, 다른 함수나 엔진 등 외부에 정보를 전달하는 목적으로 사용된다.

OS 에서도 마찬가지로, 다른 프로세스로 넘어가기 위해 기존의 프로세스를 보존하기 위한 정보를 로 저장한다.

비슷한 느낌의 용어로 가 있다.

참고자료: inpa 찬양해
잦은 은 오버헤드로 인해 오히려 성능 하락을 일으킬 수 있다.
를 위해 해당 프로세스에 대한 정보가 담긴 을 프로세스 생성과 동시에 메모리에 저장한다.
프로세스 전환을 위해서는 해당하는 프로세스의 를 읽어야하기 때문에 작업에 비해 너무 많은 프로세스는 오히려 성능 하락을 일으킬 수 있다.

비슷하게 스레드에서도 라는게 존재하여 비슷한 역할을 한다.
스레드에서는 등의 동기화 기법을 사용한다.
에서는 공유된 자원에 대한 동시 접근에 의한 문제점이 발생할 수 있다.
이는 프로세스와는 달리(프로세스도 공유하는 방법이 존재하긴한다.) 스레드는 자원을 공유하기 때문에,
이에 대한 동시 접근이 가능하며, 이로 인해 잘못 업데이트 된 경우, 이라고 부른다.

1.7.2 Threads

프로세스를 여러개의 실행 단위로 나눈 것을 라고 부른다.
하나의 프로세스에서 는 코드와 전역 데이터를 공유한다.
여러 프로세스보다 데이터를 공유하기 편하기 때문에, 효율적이며 점점 중요도가 올라가고 있다.



를 여러 개로 나눈 실행 단위.
끼리는 코드와 데이터 등 프로세스의 자원을 공유한다.

1.7.3 Virtual Memory

에 온전한 접근을 하는 것처럼 보이게 만드는 추상화를 라고 한다.
이를 통해 각각의 는 통일된 메모리에 대한 "시각"을 가진다.
이는 라고 한다.

에서는 아래의 그림과 같다. (다른 계열 시스템도 비슷하다.)
PARA/Project/CS_APP_organize/chapter1/imgs/process_virtual_address_space.png
(주소는 "아래에서 위" 방향으로 증가한다.)

가장 위는 모든 프로세스에서 공통인 OS의 코드와 데이터가 존재한다.
아래 쪽에는 유저에 의해 정의된 코드와 데이터가 존재한다.

이러한 추상화를 통해, 프로세스는 메모리를 특정한 목적으로 분리된 영역으로 이루어진 것처럼 본다.
후에 자세히 다루지만, 여기서 간단하게 다룬다. (밑에서 위 방향으로 살펴본다.)


  • 코드는 모든 프로세스가 동일한 고정된 주소에서 시작된다.
    그 다음으로 데이터 구역으로 C언어의 전역변수에 대응되는 영역이 존재한다.

    모든 프로세스가 동일한 고정된 주소를 가지면, 충돌이 나지 않을까?
    이를 방지해주는 것이 의 역할로, 각 프로세스가 보는 주소는 같지만,
    실제 메모리상의 주소는 다르다. 프로세스가 보는 주소와 실제 메모리상의 주소를, 가 맵핑해준다고 볼 수도 있다. (7장-linking 에서 더 살펴본다.)


  • 으로 는 고정된 것과는 다르게, 런타임에 동적으로 늘어나고 줄어들 수 있다. C언어에서는 malloc, free 함수를 통해 조절한다. (9장 - virtual memory에서 다룬다.)


  • 중간에는 가 존재한다. C언어에서는 예를 들어, 기본 라이브러리와 수학 라이브러리 등이 있다. 이 개념은 강력하지만, 꽤 어려운 개념으로 7장-dynamic linking에서 더 배운다.


  • 과 유사하게 동적으로 늘어나고 줄어든다.
    단, 에 이용된다. 각 함수가 호출될 때 늘어나며, 함수가 반환할 때 줄어든다.
    3장에서 자세히 다루게 된다.


  • 이 사용하는 영역으로 프로그램은 사용할 수 없다.
    이 곳에 있는 내용은 에게 요청하여 간접적으로 접근해야만 한다.

는 하드웨어와 OS 소프트웨어의 정교한 상호작용이 필요하다.
예를 들어, 물리적 주소와 가상의 주소간의 관계는 디스크에 저장되고, 로서 사용하게 된다. 9장에서 어떻게, 이것이 왜 중요한지 설명한다.

1.7.4 Files

"단순한 bytes 의 조합, 그이상 그이하도 아니다."
모든 I/O 장치, 네트워크는 file 로 모델링 된다.
모든 Input, Output 은 단순히 파일을 읽고, 쓰는 것에 대응된다.

이 작고 우아한 개념은 매우 강력하다. 다양한 I/O 장치에 대해 통일된 시각을 제공해주기 때문이다.