본문 바로가기

공부 기록/OS

[OS/공룡책] Chapter 3. 프로세스 - 프로세스 개념, 프로세스 스케줄링, 프로세스에 대한 연산

프로세스 개념

프로세스

- 프로세스란 실행 중인 프로그램이다.

- 프로세스의 메모리 배치는 일반적으로 여러 섹션으로 구분된다.

   - 텍스트 섹션 : 실행 코드

   - 데이터 섹션 : 전역 변수

   - 힙 섹션 : 프로그램 실행 중에 동적으로 할당되는 메모리

   - 스택 섹션 : 함수를 호출할 때 임시 데이터 저장 장소(예 : 함수 매개변수, 복귀 주소 및 지역 변수)

- 스택 및 힙 섹션은 프로그램 실행 중에 동적으로 줄어들거나 커질 수 있다. 스택 및 힙 섹션이 서로의 방향으로 커지더라도 운영체제는 서로 겹치지 않도록 해야 한다.

 

- 프로그램 그 자체는 프로세스가 아니다.

   - 프로그램은 명령어 리스트를 내용으로 가진 디스크에 저장된 파일(실행 파일이라고 불림)과 같은 수동적인 존재(passive entity)이다.

   - 프로세스는 다음에 실행할 명령어를 지정하는 프로그램 카운터와 관련 자원의 집합을 가진 능동적인 존재(active entity)이다.


프로세스 상태

- new : 프로세스가 생성 중이다.

- running : 명령어들이 실행되고 있다.

- waiting : 프로세스가 어떤 이벤트(예 : 입출력 완료 또는 신호의 수신)가 일어나기를 기다린다.

- ready : 프로세스가 처리기에 할당되기를 기다린다.

- terminated : 프로세스의 실행이 종료되었다.

 

- 어느 한 순간에 한 처리기 코어에서는 오직 하나의 프로세스만이 실행된다. 그렇지만, 많은 프로세스가 준비 완료(ready) 및 대기(waiting) 상태에 있을 수 있다.


프로세스 제어 블록

- 각 프로세스는 운영체제에서 프로세스 제어 블록(process control block, PCB, 태스크 제어 블록)에 의해 표현된다.

- 프로세스 제어 블록은 특정 프로세스와 연관된 여러 정보를 수록하며, 다음과 같은 것들을 포함한다. => 프로세스 상태, 프로그램 카운터, CPU 레지스터들, CPU-스케줄링 정보, 메모리 관리 정보, 회계 정보, 입출력 상태 정보

- 프로세스 제어 블록은 약간의 회계 데이터와 함께 프로세스를 시작시키거나 다시 시작시키는 데 필요한 모든 데이터를 위한 저장소의 역할을 한다.


스레드

- 대부분의 현대 운영체제는 프로세스 개념을 확장하여 한 프로세스가 다수의 실행 스레드를 가질 수 있도록 허용한다.

- 특히 다중 처리기 시스템에서, 여러 스레드가 병렬로 실행될 수 있다.

- 스레드를 지원하는 시스템에서 PCB는 각 스레드에 관한 정보를 포함하도록 확장된다.


프로세스 스케줄링

- 다중 프로그래밍의 목적은 CPU 이용을 최대화하기 위하여 항상 어떤 프로세스가 실행되도록 하는 데 있다. 시분할의 목적은 각 프로그램이 실행되는 동안 사용자가 상호 작용할 수 있도록 프로세스들 사이에서 CPU 코어를 빈번하게 교체하는 것이다. 이 목적을 달성하기 위해 프로세스 스케줄러는 코어에서 실행 가능한 여러 프로세스 중에서 하나의 프로세스를 선택한다.

- 다중 프로그래밍 및 시간 공유의 목표를 균형 있게 유지하려면 프로세스의 일반적인 동작을 고려해야 한다. I/O 바운드 프로세스는 계산에 소비하는 것보다 I/O에 더 많은 시간을 소비하는 프로세스이다. 반대로 CPU 바운드 프로세스는 계산에 더 많은 시간을 사용하여 I/O 요청을 자주 생성하지 않는다.

 

스케줄링 큐

- 프로세스가 시스템에 들어가면 준비 큐에 들어가서 준비 상태가 되어 CPU 코어에서 실행되기를 기다린다. => 이 큐는 일반적으로 연결 리스트로 저장된다.

- I/O 완료와 같은 특정 이벤트가 발생하기를 기다리는 프로세스는 대기 큐에 삽입된다.

- 프로세스 스케줄링의 일반적인 표현은 아래와 같은 큐잉 다이어그램이다.

큐잉 다이어그램

- 원은 큐에 서비스를 제공하는 자원을 나타내고 화살표는 시스템의 프로세스의 흐름을 나타낸다.


CPU 스케줄링

- CPU 스케줄러의 역할은 준비 큐에 있는 프로세스 중에서 선택된 하나의 프로세스에 CPU 코어를 할당하는 것이다.

- CPU 스케줄러는 일반적으로 훨씬 더 자주 실행되지만, 적어도 100밀리초마다 한 번씩 실행된다.

- 일부 운영체제는 스와핑으로 알려진 중간 형태의 스케줄링을 가지고 있다. => 일반적으로 메모리가 초과 사용되어 가용공간을 확보해야 할 때만 필요하다.


문맥 교환

- 인터럽트가 발생하면 시스템은 인터럽트 처리가 끝난 후에 문맥을 복구할 수 있도록 현재 실행 중인 프로세스의 현재 문맥을 저장할 필요가 있다. 이는 결국 프로세스를 중단했다가 재개하는 작업이다.

- 문맥은 프로세스의 PCB에 표현된다. 일반적으로 CPU의 현재 상태를 저장하는 작업을 수행하고(state save), 나중에 연산을 재개하기 위하여 상태 복구 작업을 수행한다(state restore).

- CPU 코어를 다른 프로세스로 교환하려면 이전의 프로세스의 상태를 보관하고 새로운 프로세스의 보관된 상태를 복구하는 작업이 필요하다. => 이 작업을 문맥 교환(context switch)이라 한다.

- 문맥 교환이 진행될 동안 시스템이 아무런 유용한 일을 못 하기 때문에 문맥 교환 시간은 순수한 오버헤드이며, 하드웨어의 지원에 크게 좌우된다.


프로세스에 대한 연산

프로세스 생성

- 프로세스는 실행되는 동안 여러 개의 새로운 프로세스들을 생성할 수 있다.(부모 프로세스 - 자식 프로세스) 이 새로운 프로세스들은 각각 다시 다른 프로세스들을 생성할 수 있으며, 그 결과 프로세스의 트리를 형성한다.

- 대부분의 현대 운영체제들은 유일한 프로세스 식별자(pid)를 사용하여 프로세스를 구분하는데 이 식별자는 보통 정수이다. => 이 식별자를 통하여 커널이 유지하고 있는 프로세스의 다양한 속성에 접근하기 위한 인덱스로 사용된다.

보편적인 Linux 시스템의 프로세스 트리

- 프로세스가 새로운 프로세스를 생성할 때, 두 프로세스를 실행시키는 데 두 가지 가능한 방법이 존재한다.

  1. 부모는 자식과 병행하게 실행을 계속한다.
  2. 부모는 일부 또는 모든 자식이 실행을 종료할 때까지 기다린다.

- 새로운 프로세스들의 주소 공간 측면에서 볼 때 다음과 같은 두 가지 가능성이 있다.

  1. 자식 프로세스는 부모 프로세스의 복사본이다.(똑같은 프로그램과 데이터를 가진다.)
  2. 자식 프로세스가 자신에게 적재될 새로운 프로그램을 가지고 있다.

프로세스 종료

- 프로세스가 마지막 문장의 실행을 끝내고, exit 시스템 콜을 사용하여 운영체제에 자신의 삭제를 요청하면 종료한다.

- 또 다른 경우는, 한 프로세스는 적당한 시스템 콜을 통해서 다른 프로세스의 종료를 유발할 수 있다. 통상적으로 그런 시스템 콜은 부모 프로세스만이 호출할 수 있다.

- 몇몇 시스템에서는 부모 프로세스가 종료한 이후에 자식 프로세스가 존재할 수 없다. 따라서 프로세스가 종료되면 그로부터 비롯된 모든 자식 프로세스들도 종료되어야 한다. => 연쇄식 종료

 

- 종료되었지만 부모 프로세스가 아직 wait()호출을 하지 않은 프로세스를 좀비(zombie)프로세스라고 한다.

- 부모 프로세스가 wait()를 호출하는 대신 종료한다면, 그 자식 프로세스를 고아(orphan)프로세스라고 부른다.

 

Android 프로세스 계층

- 안드로이드는 임의의 프로세스를 종료하지 않고 프로세스의 중요도 계층을 식별했으며, 시스템이 프로세스를 종료하여 새로운, 또는 보다 중요한 프로세스를 위한 자원을 확보해야 할 경우 중요도가 낮은 프로세스부터 종료한다.

  • 전경 프로세스 : 사용자가 현재 상호 작용하고 있는 응용 프로그램, 화면에 보이는 현재 프로세스
  • 가시적 프로세스 : 전경에서 직접 볼 수 없지만 전경 프로세스가 참조하는 활동을 수행하는 프로세스
  • 서비스 프로세스 : 사용자가 인지할 수 있는 활동을 수행하는 프로세스
  • 백그라운드 프로세스 : 활동을 수행하고 있지만 사용자가 인식하지 못하는 프로세스
  • 빈 프로세스 : 응용 프로그램과 관련된 활성 구성요소가 없는 프로세스