[운영체제] 프로세스 관리
2022. 8. 5. 15:55ㆍCS/운영체제(OS)
1. 프로세스란?
- 프로세스 : 실행 중인 프로그램, 디스크에 실행파일 형태로 존재하던 프로그램이 메모리에 올라가 실행되기 시작하면 비로소 프로세스가 된다.
- 프로세스의 문맥(context) : 프로세스가 현재 어떤 상태에서 수행되고 있는지 정확히 규명하기 위해 필요한 정보, 그 프로세스의 주소 공간(코드, 데이터, 스택)과 레지스터에 어떤 값이 있었는지, 시스템 콜을 통해 커널에서 수행한 일의 상태, 커널이 프로세스에 관해 관리하는 각종 정보 포함
① 하드웨어 문맥 : CPU의 수행 상태를 나타내는 것, 프로그램 카운터 값과 각종 레지스터에 저장하고 있는 값
② 프로세스의 주소 공간 : 코드, 데이터, 스택에 저장되고 있는 값
③ 커널상의 문맥 : OS는 프로그램이 프로세스가 되었을 때 프로세스를 관리하기 위한 자료구조를 관리한다. 여기에 해당되는 것이 PCB와 커널스택이다.
2. 프로세스의 상태
- 프로세스의 상태는 실행(running), 준비(ready), 봉쇄(blocked, wait, sleep)의 세 가지로 구분할 수 있다.
- Running : 프로세스가 CPU를 보유하고, 기계어 명령을 실행하고 있는 상태
- Ready : 프로세스가 CPU만 보유하면 당장 명령을 실행할 수 있으나, CPU를 할당받지 못한 상태
- Blocked, Waiting : CPU를 할당받더라도 당장 명령을 수행할 수 없는 상태
- 컨텍스트 스위칭 : OS에서 실행시킬 프로세스를 변경하기 위해 원래 수행중이던 프로세스의 문맥을 저장하고 새로운 프로세스의 문맥을 세팅하는 과정
- CPU 디스패치 : 준비 상태에 있는 프로세스 중 CPU를 할당받을 프로세스를 선택한 후 CPU의 제어권을 넘겨받는 과정
※ 디스크 입출력을 요청한 프로세스는??? (예시)
- 디스크 입출력을 기다리는 큐에 줄 서 있는다.
- 자기 차례가 되어 디스크 컨트롤러에서 서비스를 받고(마그네틱 매체에서 원하는 데이터를 로컬 버퍼로 읽어옴) 디스크 컨트롤러가 CPU에 입출력이 완료되었다는 인터럽트 발생시킴
- CPU는 다른 프로세스 명령을 수행하다가 인터럽트가 발생한 것을 확인하고 이에 맞는 루틴 수행
- 이 루틴이 실행되는 동안 CPU에서 수행되던 프로세스의 상태는 사용자모드 실행 상태에서 커널모드 실행 상태로 바뀐다.
- 입출력이 완료된 프로세스의 상태를 blocked에서 ready로 바꾸고 장치의 로컬 버퍼에 있는 데이터를 메모리로 이동시키는 일련의 업무를 수행한다.
- 이후에는 CPU 스케줄링 방법에 따라 어떤 프로세스에게 CPU를 이양할지 결정된다.
3. 프로세스 제어블록(PCB)
- 프로세스 제어블록 : OS가 시스템 내의 프로세스들을 관리하기 위해 프로세스마다 유지하는 정보들을 담는 커널 내의 자료구조
※ PCB를 구성하는 요소
- 프로세스의 상태 : CPU를 할당해도 되는 지 여부를 결정하기 위해 필요
- 프로그램 카운터값 : 다음에 수행할 명령의 위치
- CPU 레지스터값 : CPU 연산을 위해 현 시점에 레지스터에 어떤 값을 저장하고 있는지 나타냄
- CPU 스케줄링 정보, 메모리 관리 정보 : CPU 스케줄링과 메모리 할당을 위해 필요한 정보
- 자원 사용 정보 : 사용자에게 자원 사용 cost를 계산해 청구하는 용도
- 입출력 상태 정보 : 프로세스의 입출력 관련 상태 정보
4. 문맥교환(Context Switching)
- 문맥교환 : 하나의 사용자 프로세스로부터 다른 사용자 프로세스로 CPU 제어권이 이양되는 과정
- 사용자 프로세스가 CPU를 할당받고 실행되던 도중에 타이머 인터럽트가 발생하면 CPU의 제어권은 운영체제로 넘어간다. 그러면 운영체제는 타이머 인터럽트 처리루틴으로 가서 수행 중이던 프로세스의 문맥을 저장하고 새롭게 실행시킬 프로세스에 CPU를 이양한다.
- 이 때, 문맥이라고 함은 각 프로세스의 PCB에 저장된다.
- 문맥교환에 소요되는 시간은 시스템 입장에서 볼 때 일종의 오버헤드라고 할 수 있다. 타이머에 CPU 할당 시간을 아주 작게 설정하면 프로세스 간 문맥교환이 너무 빈번하게 일어나 오버헤드가 상당히 커질 수 있고, 크게 설정하면 시분한 시스템의 의미가 퇴색되므로 적절한 CPU 할당시간을 정하는 것이 중요하다.
5. 프로세스를 스케줄링하기 위한 큐
- OS는 준비 상태의 프로세스들을 줄 세우기 위해 준비 큐를 두고 준비 큐의 제일 앞의 프로세스에 제일 먼저 CPU를 할당한다. 준비 큐에 줄 세우는 방식은 CPU 스케줄링에 따른다.
- CPU를 기다리는 큐 이외에도 특정 디바이스를 기다리는 큐도 존재한다. 디스크 컨트롤러는 디스크 입출력 큐에 줄 서 있는 순서대로 프로세스의 입출력 작업을 수행한다.
- 하드웨어 자원 뿐 아니라 소프트웨어 자원에도 기다리는 큐는 존재한다. 공유 데이터에 대한 접근 권한같은 경우에는 임의의 프로세스가 공유 데이터에 접근하고 있을 때 다른 프로세스가 동일 데이터에 접근하게 되면 일관성이 깨어질 수 있으므로 접근 중인 프로세스가 다 사용하고 반납하기 전까지는 다른 프로세스는 기다려야 한다.
- 작업 큐(job queue) : 준비 큐와 장치 큐 이외에 운영체제가 시스템 내의 모든 프로세스를 관리하기 위한 큐로 프로세스의 상태와 무관하게 모든 프로세스가 이 작업 큐에 속하게 된다. 작업 큐에 있다고 해서 모두 메모리를 가지는 것은 아님 (준비 큐의 프로세스는 준비 상태, 장치 큐의 프로세스는 봉쇄 상태)
- 장치 큐는 각 자원마다 큐가 하나씩 존재하고 여기서 큐헤더는 큐의 가장 앞부분이다. 큐는 각 프로세스의 PCB를 연결 리스트 형태로 관리하고 포인터를 사용해 순서를 정한다.
6. 스케줄러
- 스케줄러 : 어떤 프로세스에게 자원을 할당할지 결정하는 OS 커널의 코드
※ 장기 스케줄러(long term scheduler)
- 작업 스케줄러라고도 하며, 어떤 프로세스를 준비 큐에 넣을지 결정하는 역할
- 준비 큐의 프로세스는 CPU 제어권만 얻으면 당장이라도 실행될 수 있는 집합이고 CPU에서 실행되기 위해서는 프로세스가 메모리를 보유해야 하기 때문에 장기 스케줄러는 프로세스에 메모리를 할당하는 문제에 관여한다.
- 시작 상태의 프로세스에 메모리를 할당을 승인할지 여부를 결정
- 하지만 현대의 시분할 시스템용 OS에서는 프로세스가 시작 상태가 되면 장기 스케줄러 없이 곧바로 그 프로세스에 메모리를 할당해 준비 큐에 넣어준다. (장기 스케줄러를 안씀)
※ 단기 스케줄러(short term scheduler)
- CPU 스케줄러라고도 하며, 준비 큐에 있는 프로세스들 중 어떤 프로세스에게 CPU를 할당할 것인지 결정하는 역할
- 시분할 시스템에서는 타이머 인터럽트가 발생하면 단기 스케줄러가 호출된다.
※ 중기 스케줄러(mid term scheduler)
- 너무 많은 프로세스에게 메모리를 할당해 시스템의 성능이 저하되는 것을 방지하기 위해 메모리에 적재된 프로세스의 수를 동적으로 조절하기 위해 추가된 스케줄러
- 메모리에 적재된 프로세스가 너무 많을 경우 CPU가 현재 수행해야 할 프로세스의 주소 공간조차도 메모리에 올려놓기 어려운 상황이 발생하고, 이는 빈번한 디스크 입출력을 불러일으켜 심각한 성능 저하를 초래한다.
- 중기 스케줄러는 메모리에 올라온 프로세스 중 일부의 메모리를 통째로 빼앗아 디스크의 스왑 영역에 저장해두는데, 이를 스왑 아웃(swap out)이라고 한다.
- 스왑 아웃의 우선순위 1순위는 블락 상태의 프로세스(메모리를 할당해봤자 사용 못함)이고 그 이후에도 메모리가 모자란다면 타이머 인터럽트가 발생해 준비 큐로 이동하는 프로세스를 스왑 아웃시킨다. 이를 통해 당장 실행해야 할 프로세스에 추가로 메모리를 부여함으로써 효율적인 운용이 가능하다.
- 프로세스 상태에 실행(running), 준비(ready), 봉쇄(blocked) 이외에도 중지(suspended) 상태가 추가된다. 중지 상태는 외부에서 재개시키지 않는 한 다시 활성화될 수 없으므로 메모리 자원이 당장 필요하지 않다.
- 중지 상태에서도 중지준비(suspended ready) 상태와 중지봉쇄(suspended blocked) 상태로 분화할 수 있다.
7. 프로세스의 생성
- 운영체제가 프로세스를 전부 만드는 것이 아닌 부모 프로세스와 자식 프로세스가 존재하고 부모 프로세스는 자신이 생성한 모든 후손 프로세스들을 연쇄적으로 종료시킨 후에야 종료될 수 있다.
- 프로세스는 자원을 필요로 함 : 운영체제로부터 받을 수 있고, 부모와 공유할 수 있다.
- 수행 : 부모와 자식이 공존하며 수행되는 모델이 있고, 자식이 종료(terminate)될 때까지 부모가 기다리는(wait) 모델이 있음.
※ 프로세스의 생성 절차
- 유닉스에서는 fork() 시스템 콜을 통해 새로운 프로세스 생성 가능하다. fork() 시스템 콜은 자식 프로세스를 생성할 때 부모 프로세스의 내용을 그대로 복제 생성(프로세스 id를 제외한 모든 정보, 운영체제 커널 내의 정보와 주소 공간의 정보)하게 된다.
- 부모와 자식 프로세스는 주소 공간은 다르나 내용은 같음. fork()를 통해 생성된 자식 프로세스는 exec() 시스템 콜을 통해 새로운 프로그램으로 주소 공간을 덮어씌울 수 있음
※ 프로세스의 종료
- 프로세스의 종료는 두 가지로 나눌 수 있는데, 자발적 종료와 비자발적 종료이다.
▷ 자발적 종료
- 프로세스가 명령을 모두 수행한 후 exit()이라는 시스템 콜을 만나 OS에게 자신이 종료됨을 알릴 수 있다.
- 종료를 통보받은 OS는 프로세스로부터 자원을 회수하고 시스템 내에서 이 프로세스를 정리한다.
- exit() 함수는 프로그램 개발자가 명시적으로 호출하지 않아도 컴파일러에서 프로그램이 종료되는 시점에 자동으로 삽입한다.
▷ 비자발적 종료
- 부모 프로세스가 자식 프로세스의 수행을 abort() 함수를 통해 강제로 종료시킨다.
- 강제 종료가 발생하는 케이스는 다음과 같다.
① 자식 프로세스가 할당 자원의 한계치를 넘어서는 많은 양의 자원을 요구할 때
② 자식 프로세스에 할당된 작업이 더 이상 필요치 않을 때
③ 부모 프로세스가 종료될 때
- 사용자 계정을 서버 컴퓨터에 접속해 수행시킨 프로그램을 로그아웃 후에도 계속 수행시켜야 하는 경우가 있을 수 있음 → 로그인 창 아래에 생성된 모든 자식 프로세스들이 종료된다. → 이럴 때는 해당 프로세스를 로그아웃 후에도 존재하는 시스템 프로세스의 자식으로 이양시키는 절차 필요
※ 프로세스가 자식 프로세스를 생성하는 과정
- OS는 자식 프로세스의 생성을 위해 fork() 시스템 콜 제공, 이 때 CPU 제어권이 커널로 넘어가고, 커널은 fork()를 호출한 프로세스를 복제해 자식 프로세스를 생성한다.
- 이 때 생성된 자식 프로세스는 부모 프로세스의 주소 공간을 비롯한 프로그램 카운터 등 레지스터 상태, PCB 및 커널 스택 등 모든 문맥을 그대로 복제한다. (프로세스 식별자(ID) 는 다름)
- 복제된 프로세스를 구별할 수 있는 한 가지는 fork() 함수의 결과값이 원본은 양수이고, 복제본은 0이라는 것이다.
- 이 자식 프로세스에 독자적인 프로그램을 수행시킬 수 있는 exec() 시스템 콜을 유닉스에서 지원한다. exec() 시스템 콜은 프로세스가 지금까지의 상태를 잊어버리고 그 주소 공간을 완전히 새로운 프로그램으로 덮어씌운 후 새로운 프로그램의 첫 부분부터 수행을 시작하게 한다.
- fork(), exec(), exit() 함수는 모두 사용자 프로세스가 직접 수행할 수 없는 특권명령에 해당되며, 이를 수행하기 위해서는 OS에 대행을 요청해야 한다.
- 이외에도 wait() 함수가 존재하는데 fork() 후에 wait()을 호출하면 자식 프로세스가 종료될 때까지 부모 프로세스를 봉쇄 상태로 놓으며 자식 프로세스가 종료되는 순간 부모 프로세스는 준비 큐에 재진입하여 CPU를 얻을 수 있는 권한을 획득한다.
8. 프로세스 간의 협력
- 프로세스는 각자 독립적인 주소 공간을 가지고 수행되고 임의의 프로세스가 다른 프로세스의 주소 공간을 참조하는 것은 허용되지 않는다.
- 경우에 따라선 독립적인 프로세스들이 협력함으로써 업무 효율의 증진을 가져올 수 있다. 따라서, OS는 프로세스 간의 협력 메커니즘을 제공하여 하나의 프로세스가 다른 프로세스의 수행에 영향을 미칠 수 있게 한다.
※ IPC(Inter-Process Communication)
- IPC : 하나의 컴퓨터 안에서 실행 중인 서로 다른 프로세스 간에 발생하는 통신
- 이런 통신은 의사소통 기능 뿐 아니라 동기화도 함께 보장해주어야 한다. 공유 데이터가 존재한다는 것은 서로 다른 프로세스가 동시에 접근했을 때 동시성 문제를 일으킬 수 있기 때문이다(데이터의 불일치). 따라서 공유 데이터의 값을 변경하는 동안은 다른 프로세스의 접근을 허용하지 않는다.
- IPC의 방법으로는 메시지 전달 방식과 공유 메모리 방식이 있다. (프로세스 사이에 공유 데이터 사용 여부의 차이)
▷ 메시지 전달 방식
- 프로세스 간에 공유 데이터를 일체 사용하지 않고 메시지를 주고받으면서 통신하는 방식 (두 프로세스의 주소 공간이 다르므로 직접은 불가)
- 메시지 통신을 하는 시스템은 커널에 의해 send(message)와 receive(message) 두 가지 연산을 제공받고, 이 두 연산을 통해 프로세스에서 OS로 시스템 콜 방식으로 요청하여 전달할 수 있다.
- 프로세스 간에 커뮤니케이션 링크를 구성한 후 연산을 이용해 메시지를 주고받는데, 이 커뮤니케이션 링크의 구현 방법은 물리적인 방법과 논리적인 방법이 있을 수 있다.
- 메시지의 전송 대상이 다른 프로세스인지 아니면 메일박스라는 일종의 저장공간인지에 따라 다시 나눌 수 있다.
① 직접 통신
- 통신하려는 프로세스의 이름을 명시적으로 표시 ex) send(P, message) // receive(Q, message), P와 Q가 프로세스의 이름을 지칭
- 커뮤니케이션 링크는 자동적으로 생성되고, 하나의 링크는 정확히 한 쌍의 프로세스에게 할당된다. 각 쌍의 링크는 오직 하나의 링크만이 존재하고, 단방향이 존재할 수 있으나 대부분 양방향성이다.
② 간접 통신
- 메시지를 메일박스 또는 포트로부터 전달받는다.
- 각 메일박스에는 고유의 ID가 있고, 메일박스를 공유하는 프로세스만 서로 통신을 할 수 있다.
- send(A, message) 는 A라는 메일박스에 메시지를 전송하는 것을 뜻하며, receive(A, message) 는 A라는 메일박스로부터 메시지를 전달받는 것을 뜻한다.
- 메일 박스에 만약 3개의 프로세스가 서로 공유하는 상태라면?
- 이를 해결하기 위해선 2개의 프로세스에만 링크를 할당하는 방법이나, 링크에 대한 receive() 연산을 매 시점 하나의 프로세스만 수행할 수 있도록 하는 방법이나, 시스템이 메시지 수신자를 임의로 결정해 송신자에게 어떤 프로세스가 수신했는지를 알리는 방법이 있다.
▷ 공유 메모리 방식
- 공유 메모리 방식에서는 프로세스들이 주소 공간의 일부를 공유한다.
- OS에서 공유메모리를 사용하는 시스템 콜을 지원해 서로 다른 프로세스들이 그들의 주소 공간 중 일부를 공유할 수 있도록 한다.
- 실제 구현은 프로세스 A와 B가 독자적인 주소 공간을 갖고 있으나 주소 공간이 물리적 메모리에 매핑될 때 공유메모리 주소 영역에 대해서는 동일한 물리적 메모리 주소로 매핑된다.
- 공유메모리 방식은 프로세스 간의 통신을 수월하게 만드는 인터페이스를 제공하나, 데이터의 일관성 문제에 관해서는 커널이 책임지지 않기 때문에 프로세스들끼리 직접 책임져야 한다.
'CS > 운영체제(OS)' 카테고리의 다른 글
[운영체제] 가상메모리 (0) | 2022.08.07 |
---|---|
[운영체제] 메모리 관리 (0) | 2022.08.06 |
[운영체제] CPU 스케줄링 (0) | 2022.08.05 |
[운영체제] 프로그램의 구조와 실행 (0) | 2022.08.05 |
[운영체제] 컴퓨터 시스템 (Computer System) (0) | 2022.08.04 |