[운영체제] 5. 프로세스 관리
by 콰이엇반효경 교수님의 "운영체제와 정보기술의 원리" 책을 학습하고 정리한 글입니다.
1. 프로세스의 개념
📌 프로세스 (Process)
실행 중인 프로그램 (Program in execution)
📌 프로세스의 문맥 (Context)
프로세스의 현재 상태 정보
🧐 프로세스의 문맥 정보가 필요한 이유
프로세스는 시분할 시스템 환경에서 시작 후 명령을 한 번에 수행하지 않고, 인터럽트에 의해 짧은 시간 CPU 사용 후 빼앗겼다가 다시 획득하는 방식으로 CPU 관리가 이루어진다. 따라서, CPU를 다시 획득해 명령의 수행을 재개할 때 이전까지 명령을 수행한 시점의 정확한 상태 재현이 필요하다.
✍🏻 프로세스 문맥의 세 가지 분류
- 하드웨어 문맥 : CPU의 수행 상태
- 프로그램 카운터(PC, Program Counter) 값, 각종 레지스터에 저장하고 있는 값
- 프로세스의 주소 공간 : 코드, 데이터, 스택
- 커널 상의 문맥 : 프로세스를 관리하기 위한 자료구조 (PCB, 커널 스택)
2. 프로세스의 상태
✍🏻 프로세스의 상태 3가지 + @
- 실행 (Running) : 프로세스가 CPU를 보유하고, 기계어 명령을 실행하고 있는 상태
- 준비 (Ready) : 프로세스가 CPU만 보유하면 당장 명령을 실행할 수 있지만, CPU를 할당받지 못한 상태
- 봉쇄 (Blocked, wait, stop) : CPU를 할당받더라도 당장 명령을 실행할 수 없는 상태
- 시작 (New) : 프로세스가 생성 중인 일시적 상태
프로세스가 시작되어 그 프로세스를 위한 각종 자료구조는 생성되었지만 아직 메모리 획득을 승인받지 못한 상태 - 종료 (Terminated) : 프로세스가 종료 중인 일시적 상태
프로세스가 종료되었으나 운영체제가 그 프로세스와 관련된 자료구조를 완전히 정리하지 못한 상태
📌 프로세스의 문맥 교환 (Context Switch)
실행 프로세스 변경을 위해 현재 실행 중인 프로세스의 문맥을 저장하고 새 프로세스 문맥을 세팅하는 과정
- 타이머 인터럽트가 발생하는 경우
- 실행 상태에 있던 프로세스가 입출력 요청 등으로 봉쇄 상태로 바뀌는 경우
📌 CPU 디스패치 (dispatch)
준비 상태에 있는 프로세스들 중에서 CPU를 할당받을 프로세스를 선택한 후 실제로 CPU의 제어권을 넘겨받는 과정
✍🏻 입출력을 요청한 프로세스의 상태 변화 과정
실행 상태 (Running) → 봉쇄 상태 (Blocked)
프로세스가 실행 상태에 있다는 것은 CPU를 할당 받고 기계어 명령을 하나씩 수행하는 것을 의미한다. 경우에 따라 디스크에서 파일의 내용을 읽어와야 하는 명령이 포함될 수 있다. 이럴 때 읽어온 결과가 있어야 후속 명령을 수행할 수 있는데, 디스크에서 읽는 작업은 CPU 처리 속도에 비해 상대적으로 오랜 시간이 소요되는 작업이기 때문에 디스크 입출력이 진행되는 동안에는 이 프로세스가 CPU를 점유하고 있어도 후속 명령을 처리하지 못해 CPU가 비효율적으로 낭비되는 상황이 발생하게 된다. 따라서, 입출력이 완료될 때까지 CPU를 반환한 다음 디스크 입출력 서비스를 기다리며 봉쇄 상태로 변경하게 된다.
봉쇄 상태 (Blocked) → 준비 상태 (Ready)
디스크 컨트롤러로부터 원하는 데이터를 로컬 버퍼로 읽어오고 나면 디스크 컨트롤러가 CPU에 인터럽트를 발생시켜 입출력이 완료되었다는 사실을 알린다. CPU는 인터럽트 처리 루틴에 의해 커널모드로 진입하며, 입출력이 완료된 프로세스의 상태를 봉쇄 상태에서 준비 상태로 바꾼 후 장치의 로컬버퍼에 있는 내용을 메모리로 이동시키는 일련의 업무를 수행한다.
인터럽트 처리가 끝나면 인터럽트 처리 루틴 이전에 수행되던 프로세스에게 CPU를 다시 할당해 그 프로세스의 직전 수행 시점 이후의 코드를 실행하게 된다.
일반적으로는 기존의 프로세스에 CPU를 다시 할당하지만 경우에 따라 인터럽트 당한 프로세스에게 CPU를 할당하지 않고, 더 우선순위가 높은 프로세스에 CPU 제어권을 이양할 수도 있다. (6. CPU 스케쥴링 참고)
3. 프로세스 제어블록
📌 프로세스 제어블록 (PCB, Process Control Block)
운영체제가 시스템 내의 프로세스들을 관리하기 위해 프로세스마다 유지하는 정보들을 담는 커널 내 자료구조
✍🏻 PCB의 구성 요소
- 프로세스의 상태 (Process state) : CPU 할당 가능 여부
- 프로그램 카운터 (Program counter)의 값 : 다음에 수행할 명령의 위치
- CPU 레지스터 (CPU register)의 값 : CPU 연산을 위해 현 시점에 레지스터에 어떤 값을 저장하고 있는지
- CPU 스케쥴링 정보 (CPU scheduling information) : 프로세스의 CPU 스케쥴링 정보
- 메모리 관리 정보 (Memory management information) : 프로세스 메모리 할당을 위한 정보
- 자원 사용 정보 (Accounting information) : 자원 사용 요금 청구 등의 목적
- 입출력 상태 정보 (I/O status information) : 프로세스 입출력 관련 상태 정보
4. 문맥 교환
📌 문맥 교환 (Context Switch)
하나의 사용자 프로세스로부터 다른 사용자 프로세스로 CPU 제어권이 이양되는 과정
- CPU가 다른 프로세스에게 넘어갈 때 운영체제는 다음을 수행
- CPU에 내어주는 프로세스의 상태를 그 프로세스의 PCB에 저장
- CPU를 새롭게 얻는 프로세스의 상태를 PCB에서 복원
🧐 인터럽트는 문맥 교환에 해당할까?
![](https://blog.kakaocdn.net/dn/r0GK3/btsKfJZ644t/qPQZo6TDfWVqfeZQlBBokk/img.png)
프로세스 실행 상태일 때 시스템 콜이나 인터럽트가 발생하면 CPU의 제어권이 운영체제로 넘어와 원래 실행 중이던 프로세스의 업무를 잠시 멈추고 운영체제 커널의 코드가 실행된다. CPU의 실행 위치 등 프로세스의 문맥 중 일부를 PCB에 저장하지만, 이러한 과정을 문맥 교환이라고 하지는 않는다.
이는 하나의 프로세스의 실행모드만이 user mode에서 kernel mode로 바뀌는 것일 뿐, CPU를 점유하는 프로세스가 다른 사용자 프로세스로 변경되는 과정이 아니기 때문이다. 이와 같은 모드 변경에 비해 문맥 교환에는 훨씬 많은 오버헤드(overhead)가 뒤따르게 된다.
따라서, 타이머에 CPU 할당시간을 아주 적게 설정하여 문맥 교환이 빈번하게 발생하면 오버헤드가 상당히 커진다. 반대로 CPU 할당시간을 너무 크게 설정하면 시분할 시스템의 의미가 퇴색되므로 적절한 CPU 할당시간 분배가 중요하다.
5. 프로세스를 스케쥴링하기 위한 큐
운영체제는 준비 상태에 있는 프로세스들을 줄 세우기 위해 준비 큐(ready queue)를 두고 준비 큐의 제일 앞에 줄 서 있는 프로세스에 제일 먼저 CPU를 할당한다. 준비 큐에 프로세스를 줄 세우는 방법은 CPU 스케쥴링 방법에 따라 달라진다. (6. CPU 스케쥴링 참고)
CPU 프로세스 스케쥴링 큐 외에도 특정 자원을 기다리는 프로세스를 줄 세우기 위해 자원 별로 장치 큐(device queue)를 둔다.
📌 Ready queue
현재 메모리 내에 있으면서 CPU를 할당받아 실행되기를 기다리는 프로세스의 집합
📌 Device queue
I/O device의 처리를 기다리는 프로세스의 집합
⇒ 하드웨어 자원을 기다리는 프로세스들을 줄 세우기 위한 스케쥴링 큐
🧐 소프트웨어 자원을 기다리는 큐도 있을까?
어떤 프로세스가 공유 데이터를 사용하는 중에 다른 프로세스가 같은 데이터를 접근하면 데이터에 대한 일관성이 훼손된다. 따라서, 여러 프로세스가 공유 데이터에 동시에 접근하려고 할 경우, 그 데이터를 사용하고 있는 프로세스가 데이터를 반납하기 전까지는 접근하지 못하게 하고, 반납할 경우 큐에 줄 서 있는 순서대로 데이터의 접근 권한을 주는 방법을 사용한다.
📌 작업 큐 (job queue)
시스템 내의 모든 프로세스를 관리하기 위한 큐
6. 스케쥴러
📌 스케쥴러 (Scheduler)
어떤 프로세스에게 자원을 할당할지를 결정하는 운영체제 커널의 코드
6-1. 장기 스케쥴러
📌 장기 스케쥴러 (Long term scheduler)
작업 스케쥴러(job scheduler) 라고도 부르며, 어떤 프로세스를 준비 큐에 진입시킬지 결정하는 역할
✍🏻 장기 스케쥴러의 역할
준비 큐(Ready queue)는 CPU를 획득하면 당장 실행할 수 있는 프로세스의 집합이고, CPU에서 실행되기 위해서는 프로세스가 메모리를 보유해야 하므로, 장기 스케쥴러는 프로세스에게 메모리를 할당하는 문제에 관여한다.
즉, 시작 상태의 프로세스들 중 어떠한 프로세스를 준비 큐에 삽입할 것인지 결정하는 역할을 담당한다.
- 수십초 내지 수 분 단위로 가끔 호출되기 때문에 상대적으로 속도가 느린 것을 허용
- 메모리에 동시에 올라가 있는 프로세스의 수(degree of multiprogramming)를 조절하는 역할
✍🏻 중기 스케쥴러의 등장
그러나 현대의 시분할 시스템에서 사용하는 운영체제는 일반적으로 장기 스케쥴러를 두지 않는다. 과거에 자원이 매우 빈약하던 시절에 주로 사용하고, 현대의 시분할 시스템용 운영체제에서는 프로세스가 시작되면 곧바로 메모리를 할당해 준비 큐에 넣어준다.
⇒ 현대의 시분할 시스템용 운영체제에서는 장기 스케쥴러 대신 중기 스케쥴러를 두는 경우가 많다.
6-2. 단기 스케쥴러
📌 단기 스케쥴러 (Short term scheduler)
CPU 스케쥴러라고도 하며, 준비 상태의 프로세스 중 어떤 프로세스를 실행 상태로 만들지 결정하는 역할
✍🏻 단기 스케쥴러의 역할
준비 큐에 있는 여러 프로세스들 중 어떠한 프로세스에게 CPU를 할당할 것인지 결정하는 역할
- 시분할 시스템에서는 타이머 인터럽트가 발생하면 단기 스케쥴러가 호출된다.
- 밀리초 정도의 시간 단위로 매우 빈번하게 호출되기 때문에 수행 속도가 충분히 빨라야 한다.
6-3. 중기 스케쥴러
📌 중기 스케쥴러 (Medium term scheduler)
메모리에 적재된 프로세스의 수를 동적으로 조절하기 위해 추가된 스케쥴러
✍🏻 중기 스케쥴러의 역할
너무 많은 프로세스가 메모리에 적재되어 프로세스 당 보유하고 있는 메모리 양이 극도로 적어지면 CPU 수행에 당장 필요한 프로세스의 주소 공간조차도 메모리에 올려놓기 어려운 상황이 발생한다. 그렇게 되면 디스크 입출력이 수시로 발생하여 시스템 성능이 심각하게 저하될 수 있다. 즉, 프로세스당 보유 메모리 양이 지나치게 적을 때 이를 완화하기 위해 스왑 아웃시키는 역할
📌 스왑 아웃 (Swap out)
메모리에 올라와 있는 프로세스 중 일부를 선정해 메모리를 통째로 빼앗아 디스크의 스왑 영역에 저장하는 행위
✍🏻 스왑 아웃 우선순위
- 봉쇄 상태의 프로세스
- 당장 CPU 획득 가능성이 없기 때문에 메모리를 보유하는 것 또한 큰 의미가 없기 때문
- 타이머 인터럽트가 발생해 준비 큐로 이동하는 프로세스
- 준비 큐에 너무 많은 프로세스들이 존재하면 개별 프로세스에 배정되는 메모리 양이 지나치게 적고, CPU를 할당 받은 후 다시 할당 받기까지 오랜 시간이 소요되기 때문
즉, 중기 스케쥴러는 장기 스케쥴러와 같이 메모리에 올라와 있는 프로세스의 수를 조절하는 역할 수행
✍🏻 중기 스케쥴러 등장에 따른 프로세스 상태 추가
- 중지 (Suspended, stopped) : 외부적인 이유로 프로세스의 수행이 정지된 상태
- 중지준비 상태 (Suspended ready) : 준비 상태의 프로세스가 중기 스케쥴러에 의해 스왑 아웃된 상태
- 중지봉쇄 상태 (Suspended block) : 봉쇄 상태의 프로세스가 중기 스케쥴러에 의해 스왑 아웃된 상태
⇒ 중지 상태의 프로세스들은 메모리를 조금도 보유하지 않고 디스크에 통째로 스왑 아웃된 상태로 존재
7. 프로세스의 생성
운영체제가 모든 프로세스를 생성하지는 않는다. 시스템이 부팅된 후 최초의 프로세스는 운영체제가 직접 생성하지만, 그 다음부터는 이미 존재하는 프로세스가 다른 프로세스를 복제 생성하게 된다. 이러한 방식을 통해 프로세스는 족보와 같은 트리 계층을 형성하게 된다.
프로세스의 세계에서는 자식이 먼저 죽고, 이에 대한 처리는 자식을 생성했던 부모 프로세스가 담당하는 방식으로 구성되어 있다. 어떤 프로세스가 종료될 경우 그 프로세스가 생성한 모든 자식 프로세스를 연쇄 종료시켜야 본인이 종료될 수 있다.
✍🏻 프로세스의 자원
- 운영체제로부터 직접 자원을 할당
- 부모 프로세스와 자원을 공유하여 사용
✍🏻 프로세스의 수행
- 부모와 자식이 공존하며 수행 ⇒ CPU 획득을 위해 경쟁하는 관계
- 부모가 자식의 종료를 기다리는 모델 ⇒ 자식 프로세스가 종료될 때까지 Blocked 상태로 대기
📌 부모 프로세스 : 프로세스를 생성한 프로세스
📌 자식 프로세스 : 부모 프로세스에 의해 새롭게 생성된 프로세스
✍🏻 프로세스의 생성 절차
- 부모의 주소 공간을 복사
- 새로운 주소 공간에 새로운 프로그램을 덮어 씌움
✍🏻 프로세스 생성을 위한 시스템 콜
- fork() : 자식 프로세스를 생성할 때 부모 프로세스의 내용을 그대로 복제 생성
⇒ 프로세스 ID를 제외한 모든 정보를 그대로 복사 - exec() : 새로 생성한 주소 공간에 새로운 프로그램으로 덮어 씌움
✍🏻 프로세스의 종료
- 자발적 종료 : 프로세스는 명령을 모두 수행한 후 프로그램을 마치는 코드 부분에 exit() 시스템 콜로 종료
- 비자발적 종료
- 키보드로 kill, break 등으로 강제 종료 시킬 경우자식 프로세스 종료
- 자식이 할당 자원의 한계치를 넘어서는 많은 양의 자원을 요구할 때
- 자식 프로세스에게 할당된 작업이 더 이상 필요하지 않을 때
- 부모 프로세스가 종료되는 경우
⇒ 운영체제는 부모 프로세스가 종료하는 경우 자식이 더 이상 수행되도록 두지 않는다.
- 키보드로 kill, break 등으로 강제 종료 시킬 경우자식 프로세스 종료
✍🏻 프로세스 종료를 위한 시스템 콜
- exit() : 마지막 명령을 수행한 후 운영체제에게 프로세스의 종료를 알림
- abort() : 자식 프로세스의 수행을 강제로 종료
🧐 자식 프로세스 생성 과정
- 자식 프로세스 생성을 위한 fork() 시스템 콜
- fork() 시스템 콜을 호출한 프로세스를 복제하여 똑같은 프로세스 생성
- 새로 생성한 프로세스는 부모 프로세스와 모든 문맥을 동일하게 가져, 부모 프로세스가 현재 수행한 시점(프로그램 카운터 지점)부터 수행하게 된다. 다만, 운영체제가 프로세스 관리를 위해 사용하는 프로세스 식별자만 다르게 가지게 된다.
- ⇒ fork() 함수의 결과값으로 원본에게는 양수, 복제본에게는 0을 준다.
- fork() 시스템 콜을 통한 결과값의 차이에 따라 조건문으로 다른 작업을 수행시킬 수 있다.
- 이때, 자식 프로세스에게 다른 독자적인 프로그램을 수행시키기 위해 exec() 시스템 콜을 지원한다.
프로세스와 관련된 시스템 콜 (fork(), exec(), exit(), wait())은 사용자 프로세스가 직접 수행할 수 없는 특권 명령에 해당한다.
- wait() : 자식 프로세스가 종료될 때까지 blocked 상태로 대기하고, 종료되면 ready 상태로 변경
8. 프로세스 간 협력
📌 독립적 프로세스 (Independent process)
프로세스는 각자의 주소 공간을 가지고 수행하므로 원칙적으로 다른 프로세스의 수행에 영향을 미치지 못함
📌 협력 프로세스 (Cooperating process)
프로세스 협력 매커니즘을 통해 하나의 프로세스가 다른 프로세스의 수행에 영향을 미칠 수 있음
📌 프로세스 간 협력 매커니즘 (IPC, InterProcess Communication)
하나의 컴퓨터 안에 실행 중인 서로 다른 프로세스 간에 발생하는 통신
⇒ 의사소통 기능과 동기화를 보장 (하나의 프로세스가 공유 데이터 값을 변경하는 동안 다른 프로세스는 접근 불가)
- 메시지 전달 방식 (Message passing)
프로세스 간에 공유 데이터를 일체 사용하지 않고 메시지를 주고 받으면서 통신하는 방식- 커널을 통해 커뮤니케이션 링크를 생성 후 send()와 receive()라는 두 가지 메서드 이용 (특권 명령)
- 공유 메모리 방식 (Shared memory)
서로 다른 프로세스 간에 주소 공간의 일부를 공유하는 방식- 프로세스를 서로 신뢰할 수 있는 경우 사용
- 프로세스 간 통신이 수월하게 하지만 일관성 문제 가능성 존재
✍🏻 메시지 전달 방식의 종류
연산 인터페이스에 대한 차이 (내부 구현은 사실상 동일)
- 직접 통신 (Direct Communication)
통신하려는 프로세스의 이름을 명시적으로 표시- send(P, message) : 프로세스 P에게 메시지를 전송하는 것
- receive(Q, message) : 프로세스 Q로부터 메시지를 전달받는 것
- ⇒ 링크는 자동으로 생성되고, 하나의 링크는 정확히 한 쌍의 프로세스에게 할당
- 간접 통신 (Indirect Communication)
메시지를 메일 박스(mail box) 또는 포트(port)로부터 전달- 각 메일 박스에는 고유의 ID가 있으며 메일 박스를 공유하는 프로세스들만 서로 통신할 수 있다
- send(A, message) : A라는 메일박스에서 메시지를 전송하는 것
- receive(A, message) : A라는 메일박스에서 메시지를 전달받는 것
- ⇒ 링크는 프로세스 간에 메일박스를 공유하는 경우에만 생성
🧐 P1, P2, P3가 메일박스 A를 공유하는 경우 P1이 메시지를 보냈다면 P2, P3 중 메시지를 받는 것은?
- 2개의 프로세스에게만 링크를 할당하는 방법이 사용될 수 있음
- 링크에 대한 receive() 연산을 매 시점 하나의 프로세스만 수행할 수 있도록 함
참고자료
- 책 - 운영체제와 정보기술의 원리 (반효경, 2020년 5월)
'컴퓨터과학 > 운영체제' 카테고리의 다른 글
[운영체제] 프로세스와 쓰레드 (0) | 2024.10.25 |
---|---|
[운영체제] 컴퓨터 3계층 구조 (0) | 2024.10.22 |
[운영체제] 4. 프로그램의 구조와 실행 (0) | 2024.10.21 |
[운영체제] 3. 컴퓨터 시스템의 동작 원리 (0) | 2024.10.16 |
[운영체제] 2. 운영체제 개요 (0) | 2024.10.10 |
블로그의 정보
콰이엇의 개발기록
콰이엇