프로세스의 개념
프로세스
: 실행 중인 프로그램, 일반적으로 잡(job)이라는 용어와 혼용해서 사용- 프로세스의
문맥
: 프로세스가 현재 어떤 상태에서 수행되고 있는지 정확히 규명하기 위해 필요한 정보- 명령을 수행하는 동안 계속 CPU를 빼앗겼다가 획득하는 과정을 반복하기 때문에 수행을 재개하기 위해 직전 수행 시점의 정확한 상태를 재현해야 함
- 즉, 프로세스의 문맥은 프로세스의 주소 공간(코드, 데이터, 스택)을 비롯해 레지스터에 어떤 값을 가지고 있었는지, 시스템 콜 등을 통해 커널에서 수행한 일의 상태, 그 프로세스에 관해 커널이 관리하고 있는 각종 정보 등을 포함
- 하드웨어 문맥
- CPU의 수행 상태를 나타내는 것
- 프로그램 카운터값과 각종 레지스터에 저장하고 있는 값들을 의미
- 프로세스의 주소공간
- 코드, 데이터, 스택으로 구성된 자신만의 독자적 주소 공간
- 커널상의 문맥
- PCB와 커널스택 : 운영체제가 프로세스를 관리하기 위해 가지는 자료구조
프로세스의 상태
- 컴퓨터의 자원을 효율적으로 관리하기 위해 프로세스의 상태를 구분
- 실행 (running)
- 프로세스가 CPU를 보유하고, 기계어 명령을 실행하고 있는 상태
- CPU는 하나뿐이므로, 여러 프로세스가 동시에 수행되는 것처럼 보여도 실제 실행 상태에 있는 프로세스는 매 시점 하나뿐
- 준비 (ready)
- 프로세스가 CPU만 보유하면 당장 명령을 실행할 수 있지만 CPU를 할당받지 못한 상태
- 봉쇄 (blocked, wait, sleep)
- 프로세스가 CPU를 할당받더라도 당장 명령을 실행할 수 없는 상태
- ex. 요청한 입출력 작업이 진행중인 경우
- 그 외 : 일시적 상태
- 시작 (new) : 프로세스가 생성중, 프로세스가 시작되어 각종 자료구조는 생성되었지만 아직 메모리 획득을 승인받지 못한 상태
- 완료 (terminated) : 프로세스가 종료중, 프로세스가 종료되었지만 운영체제가 자료구조를 완전히 정리하지 못한 상태
문맥교환
: 실행시킬 프로세스를 변경하기 위해 원래 수행 중이던 프로세스의 문맥을 저장하고 새로운 프로세스의 문맥을 세팅하는 과정- 문맥교환이 일어나는 경우
- 타이머 인터럽트가 발생한 경우
- 실행 상태에 있던 프로세스가 입출력 요청 등으로 봉쇄 상태로 바뀌는 경우
- 디스패치(scheduler dispatch) : 준비상태에 있는 프로세스가 CPU를 넘겨받아 실행상태가 되는 과정
프로세스 제어블록
- PCB : 운영체제가 시스템 내의 프로세스들을 관리하기 위해 프로세스마다 유지하는 정보들을 담는 커널 내의 자료구조
- 프로세스의 상태 : CPU를 할당해도 되는지 여부 결정위해 필요
- 프로그램 카운터의 값 : 다음 수행할 명령의 위치를 가리킴
- CPU 레지스터의 값 : CPU 연산을 위해 현 시점에 레지스터에 어떤 값을 저장하고 있는지
- CPU 스케줄링 정보
- 메모리 관리 정보
- 자원 사용 정보
- 입출력 상태 정보
문맥교환
- 문맥교환 : 하나의 사용자 프로세스로부터 다른 사용자 프로세스로 CPU의 제어권이 이양되는 과정
- 문맥교환이 일어나는 경우
- 타이머 인터럽트가 발생한 경우
- 실행 상태에 있던 프로세스가 입출력 요청 등으로 봉쇄 상태로 바뀌는 경우
- 과정
- 타이머 인터럽트가 발생
- CPU의 제어권이 운영체제에게 넘어감
- 운영체제는 타이머 인터럽트 처리루틴으로 가서 직전까지 수행 중이던 프로세스의 문맥을 저장하고 새롭게 실행시킬 프로세스에게 CPU를 이양
- 원래 수행 중이던 프로세스는 준비 상태로 바뀌고 새롭게 CPU를 할당받은 프로세스는 실행 상태가 됨
- 기존 프로세스는 프로그램 카운터값 등 프로세스의 문맥을 자신의 PCB에 저장 하고, 새로운 프로세스는 예전에 저장했던 자신의 문맥을 PCB로부터 실제 하드웨어로 복원시킴
- 프로세스가 실행 상태일 때 시스템 콜이나 인터럽트가 발생해서 CPU의 제어권이 운영체제로 넘어갈 때도 CPU의 실행 위치 등 프로세스의 문맥 중 일부를 PCB에 저장하지만 이 때는 문맥교환이라고 하지않음 ⇒ 하나의 프로세스의 실행모드만이 사용자모드 ↔ 커널모드 로 바뀌는 것일뿐, CPU를 점유하는 프로세스가 다른 프로세스로 변경되는 것이 아니기 때문
- 위와 같은 모드 변경보다 문맥교환이 훨씬 오버헤드가 큼
⇒ 즉, 커널모드 전후로 CPU를 점유하는 사용자 프로세스가 바뀌는 경우만 문맥교환이다.
프로세스를 스케줄링하기 위한 큐
- 운영체제는 준비 상태의 프로세스들을 줄 세우기 위해 준비 큐(ready queue)를 두고 제일 앞에 서있는 프로세스에게 먼저 CPU를 할당 ⇒ 줄 세우는 방법은 CPU 스케줄링에 따라 다름
- 준비 큐 외에도 특정 자원을 기다리는 프로세스들을 줄 세우기 위해 자원별로 장치 큐(device queue)를 둠
- 하드웨어 자원 : 디스크 입출력 큐, 키보드 입출력 큐 등
- 소프트웨어 자원 : 공유 데이터에 대한 접근
- 어떤 프로세스가 공유 데이터를 접근하는 중에 입출력 요청 등으로 인해 봉쇄 상태나 준비 상태로 변경된 경우에도 다른 프로세스가 접근하면 안 되므로 다른 프로세스가 CPU를 할당받았다고 하더라도 기존 프로세스가 자원을 반납할 때까지 큐에서 기다렸다가 받아야 함
- 운영체제는 앞서 나온 두 가지 큐 외에 작업 큐(job queue)를 추가로 유지
- 시스템 내의 모든 프로세스를 관리하기 위한 큐
- 프로세스의 상태와 무관하게 현재 시스템 내에 있는 모든 프로세스가 속함 ⇒ 작업 큐에 있다고 해서 반드시 메모리를 가지는 것은 아님
- 작업큐가 가장 넓은 개념이고 준비큐와 장치큐에 있는 프로세스들은 모두 작업큐에 속해 있음
- 프로세스의 상태 관리는 커널의 주소 영역 중 데이터 영역에 다양한 큐를 두어 수행
스케줄러
- 스케줄러 : 어떤 프로세스에게 자원을 할당할지 결정하는 운영체제 커널의 코드
- 장기 스케줄러 (long term scheduler), 작업 스케줄러 (job scheduler)
- 어떤 프로세스를 준비 큐에 진입시킬지 결정하는 역할
- 처음 생성되어 시작상태의 프로세스들 중 어떠한 프로세스를 준비 큐에 삽입할 것인지 결정
- 가끔 호출되기 때문에 상대적으로 속도가 느린 것이 허용됨
- 메모리에 동시에 올라가 있는 프로세스의 수를 조절 ⇒ 시작 상태의 프로세스에게 메모리 할당을 승인할지 여부를 결정하기 때문
- 현대의 시분할 시스템에서는 일반적으로 장기 스케줄러를 두지 않음, 프로세스가 시작 상태가 되면 장기 스케줄러 없이 곧바로 프로세스에 메모리를 할당해 준비 큐에 넣음
- 단기 스케줄러 (short term scheduler), CPU 스케줄러
- 어떤 프로세스에게 CPU를 할당할 것인가를 결정하는 역할
- 준비 상태의 프로세스 중 어떤 프로세스를 실행 상태로 만들 것인지 결정
- 시분할 시스템에서는 타이머 인터럽트가 발생하면 단기 스케줄러가 호출됨
- 짧은 단위로 빈번하게 호출되기 때문에 수행속도가 충분히 빨라야 함
- 중기 스케줄러 (medium term scheduler)
- 현대의 시분할 시스템용 운영체제에서 장기 스케줄러 대신 두는 것
- 너무 많은 프로세스에게 메모리를 할당해 시스템의 성능이 저하되는 경우 이를 해결하기 위해 메모리에 적재된 프로세스의 수를 동적으로 조절
- 스왑 아웃 (swap out) : 메모리에 올라와 있는 프로세스 중 일부를 선정해 메모리를 통째로 빼앗아 그 내용을 디스크의 스왑 영역에 저장
- 스왑 아웃 0순위 : 봉쇄 상태에 있는 프로세스들 (당장 CPU를 획득할 가능성이 없기 때문)
- 그다음 순위 : 타이머 인터럽트가 발생해 준비 큐로 이동하는 프로세스
⇒ 이러한 방식으로 장기 스케줄러와 마찬가지로 메모리에 올라와 있는 프로세스의 수를 조절
- 중지 상태 (suspended, stopped)
- 외부적인 이유로 프로세스의 수행이 정지된 상태 (ex. 중기 스케줄러)
- 외부에서 재개시키지 않는 이상 다시 활성화 될 수 없음
- 중지준비 상태 (suspended ready)
- 준비 상태에 있던 프로세스가 중기 스케줄러에 의해 디스크로 스왑아웃 된 경우
- 중지봉쇄 상태 (suspended blocked)
- 봉쇄 상태에 있던 프로세스가 중기 스케줄러에 의해 디스크로 스왑아웃 된 경우
- 중지봉쇄 상태에서 봉쇄되었던 조건을 만족하면 중지준비로 바뀜
프로세스의 생성
- 부팅 후 최초의 프로세스는 운영체제가 직접 생성하지만 그다음부터는 이미 존재하는 프로세스가 다른 프로세스를 복제 생성함
- 부모 프로세스 : 프로세스를 생성한 프로세스
- 자식 프로세스 : 새롭게 생성된 프로세스
- 부모 프로세스가 자식 프로세스를 생성함
- 반드시 자식이 먼저 죽고, 이에 대한 처리를 부모 프로세스가 담당하는 방식
- 부모와 자식이 공존하며 수행되는 모델
- 자식과 부모가 같이 CPU 획득을 위해 경쟁하는 관계
- 자식이 종료될 때까지 부모가 기다리는 모델
- 자식이 종료될 때까지 부모는 아무 일도 하지 않고 봉쇄 상태, 자식이 종료되면 그때서야 준비 상태가 되어 다시 CPU 얻을 권한이 생김
- fork() : 부모를 그대로 복사 (주소 공간을 비롯해 프로그램 카운터 등 레지스터 상태, PCB 및 커널스택 등 모든 문맥을 그대로 복사)
- 자식 프로세스는 부모가 현재 수행한 시점부터 수행하게 됨
- 자식과 부모는 PID (프로세스 식별자)만 다름
- 결과값으로 부모는 양수, 자식은 0을 받음
- exec() : 지금까지 수행했던 상태를 잊어버리고 그 주소 공간을 완전히 새로운 프로그램으로 덮어씌운 후 새로운 프로그램의 첫 부분부터 다시 실행
⇒ 새로운 프로그램을 수행시키기 위해서는 fork()를 통해 복제한 후 exec)을 통해 덮어씌우면 됨
- wait() : 자식이 종료되기를 기다리며 부모가 봉쇄상태에 머무르도록 할 때
- fork() 후 wait()을 호출하면 자식이 종료될 때까지 부모를 봉쇄 상태에 머무르게 하고, 자식이 종료되면 부모를 준비 상태로 변경시켜 작업 재개
프로세스 간의 협력
- 원칙적으로 하나의 프로세스는 다른 프로세스의 수행에 영향을 미칠 수 없지만, 경우에 따라서 프로세스들이 협력할 때 효율성이 증진될 수 있음
- IPC (Inter-Process Communication)
- 하나의 컴퓨터 안에서 실행 중인 서로 다른 프로세스 간에 발생하는 통신, 의사소통 기능과 함께 동기화를 보장해주어야 함
- 프로세스들 간 통신과 동기화를 이루기 위한 매커니즘
- 공유 데이터 (shared data) 사용여부에 따라 두 가지 방법
- 메시지 전달 (message passing)
- 프로세스 간 공유데이터를 일체 사용하지 않고 메시지를 주고받으며 통신하는 방식
- 두 프로세스는 주소 공간이 다르므로 직접 전달할 수 없고, 커널이 그 역할을 함
- 직접통신 : 통신하려는 프로세스의 이름을 명시적으로 표시, 링크 자동생성, 하나의 링크는 정확히 한 쌍의 프로세스에게 할당, 각 쌍에게는 오직 하나의 링크만 존재, 링크는 대부분 양방향성
- 간접통신 : 메시지를 메일박스 또는 포트로부터 전달받음, 메일박스를 공유하는 프로세스들만 서로 통신가능, 하나의 링크가 여러 프로세스에게 할당될 수 있고, 각 프로세스 쌍은 여러 링크 공유 가능, 링크는 단방향성 또는 양방향성
- 공유메모리 (shared memory)
- 프로세스들이 주소 공간의 일부를 공유
- 각자의 주소 공간에 공통적으로 포함되는 영역이므로 여러 프로세스가 읽고 쓰는 것이 가능
- ❌ 데이터 일관성 문제가 유발될 수 있지만, 커널이 책임지지 않기 때문에 프로세스들끼리 직접 문제를 책임져야 함