728x90
1. 프로세스의 개념
- 프로세스(process) : 실행 중인 프로그램(program in execution)
- 일반적으로 잡(job)이라는 용어와 프로세스를 혼용해 사용하기도 한다.
- 프로세스의 문맥(context) : 프로세스가 현재 어떤 상태에서 수행되고 있는지 정확히 규명하기 위해 필요한 정보
- 프로세스는 시작해서 종료할 때까지 CPU에서 명령을 한꺼번에 수행하지 않고 시분할 시스템에 의해 짧은 시간 동안 반복해서 수행된다. 이때 명령의 수행을 재개하는 경우 직전 수행 시점의 정확한 상태를 재현하기 위해 문맥이 필요하다.
- 프로세스의 문맥은 그 프로세스의 주소 공간, 레지스터에 어떤 값을 가지고 있었는지, 시스템 콜 등을 통해 커널에서 수행한 일의 상태, 그 프로세스에 관해 커널이 관리하고 있는 정보 등을 포함한다.
- 프로세스의 문맥은 크게 세 가지로 분류할 수 있다.
- 하드웨어 문맥 : CPU의 수행 상태를 나타내는 것으로 PC 값과 각종 레지스터에 저장하고 있는 값들을 의미한다.
- 프로세스의 주소 공간 : 코드, 데이터, 스택으로 구성되는 자기 자신만의 독자적인 주소 공간
- 커널상의 문맥 : 운영체제가 프로세스를 관리하기 위한 자료구조로 PCB와 커널 스택이 있다.
2. 프로세스의 상태
- 프로세스의 상태는 실행, 준비, 봉쇄의 세 가지로 구분할 수 있다.
- 실행(running) : 프로세스가 CPU를 보유하고, 기계어 명령을 실행하고 있는 상태. 컴퓨터 내에서 여러 프로세스가 동시에 수행된다고 해도 CPU는 하나뿐이므로 실제로 실행 상태인 프로세스는 매 시점 하나뿐이다.
- 준비(ready) : 프로세스가 CPU만 보유하면 당장 명령을 실행할 수 있지만 CPU를 할당받지 못한 상태
- 봉쇄(blocked, wait, sleep) : CPU를 할당받더라도 당장 명령을 실행할 수 없는 상태
- 이 밖에도 시작 상태, 완료 상태도 있다.
- 시작(new) : 프로세스가 시작되어 프로세스를 위한 각종 자료구조는 생성되었지만 아직 메모리 획득을 승인받지 못한 상태
- 완료(terminated) : 프로세스가 종료되었으나 운영체제가 그 프로세스와 관련된 자료구조를 완전히 정리하지 못한 상태
- 하나의 프로세스는 항상 위 다섯 상태 중 어느 한 상태에 머무르게 된다.
- 문맥 교환(context switch) : 실행시킬 프로세스를 변경하기 위해 원래 수행 중이던 프로세스의 문맥을 저장하고 새로운 프로세스의 문맥을 세팅하는 과정. 프로세스가 입출력 요청 등으로 봉쇄 상태로 바뀌는 경우에도 발생한다.
- CPU 디스패치(dispatch) : 준비 상태에 있는 프로세스들 중 CPU를 할당받을 프로세스를 선택한 후 실제로 CPU의 제어권을 넘겨받는 과정
3. 프로세스 제어블록
- 프로세스 제어블록(PCB) : 운영체제가 시스템 내의 프로세스들을 관리하기 위해 프로세스마다 유지하는 정보들을 담는 커널 내의 자료구조
- PCB는 다음과 같은 요소들로 구성되어 있다.
- 프로세스의 상태 : CPU 할당 가능 여부
- PC 값 : 다음에 수행할 명령의 위치
- CPU 레지스터 값 : CPU 연산을 위해 현 시점에 레지스터에 저장한 값
- CPU 스케쥴링 정보
- 메모리 관리 정보
- 자원 사용 정보 : 사용자에게 자원 사용 요금을 계산해 청구하는 등의 용도로 사용
- 입출력 상태 정보 : 프로세스의 입출력 관련 상태 정보
4. 문맥 교환
- 문맥 교환 중 원래 CPU를 보유하던 프로세스는 프로세스의 문맥을 자신의 PCB에 저장하고, 새롭게 PCB를 할당받을 프로세스는 예전에 저장했던 문맥을 PCB로부터 실제 하드웨어로 복원시킨다.
- 인터럽트가 발생해 운영체제의 커널 코드가 실행되는 경우 프로세스 문맥 중 일부를 PCB에 저장하기는 하지만 이를 문맥 교환이라고 하지는 않는다. 이는 하나의 프로세스의 실행모드가 사용자 모드에서 커널 모드로 바뀌는 것뿐이기 때문이다.
- 오직 인터럽트 후에 다른 사용자 프로세스가 CPU를 이양받는 경우에만 문맥 교환이 일어난다.
- 문맥 교환에 소요되는 시간은 시스템 입장에서 볼 때 일종의 오버헤드라고 할 수 있어, 시분할 시스템에서 CPU 할당 시간을 짧게 잡으면 문맥 교환이 지나치게 많이 발생하고, 길게 잡으면 시분할 시스템의 의미가 퇴색하게 되므로 적절한 CPU 할당 시간을 정하는 것이 중요하다.
5. 프로세스를 스케쥴링하기 위한 큐
- 준비 큐(ready queue) : 준비 상태에 있는 프로세스들의 줄로 준비 큐의 제일 앞에 줄 서 있는 프로세스에게 먼저 CPU를 할당한다. 줄 세우는 방법은 CPU 스케쥴링 방법에 따라 달라진다.
- 장치 큐(device queue) : 특정 자원을 기다리는 프로세스들의 줄. 예를 들어 디스크에 입출력 서비스를 요청한 프로세스들은 디스크 입출력 큐(disk I/O queue)에 줄 서게 된다.
- 위 큐들은 하드웨어 자원을 기다리는 프로세스들의 줄이었고, 소프트웨어 자원을 기다리는 경우에도 큐가 필요하다. 공유 데이터에 대한 큐가 그 예시인데, 이 경우에는 하드웨어를 위한 큐와 달리 공유 데이터에 접근 중인 프로세스가 준비 상태나 봉쇄 상태로 변경된 경우에도 데이터를 반납하기 전까지는 다른 프로세스가 데이터에 접근하지 못하게 해야 한다.
- 프로세스의 상태 관리는 커널의 주소 영역 중 데이터 영역에 다양한 큐를 두어 수행한다.
- 작업 큐(job queue) : 시스템 내의 모든 프로세스를 관리하기 위한 큐. 프로세스의 상태와 무관하게 모든 프로세스가 들어있다. 그러므로 작업 큐에 있다고 해서 반드시 메모리를 가지고 있는 것은 아니다. 준비 큐와 장치 큐에 있는 프로세스들은 모두 작업 큐에 속해 있다.
- 큐는 각 프로세스의 PCB를 linked list 형태로 관리하며 포인터를 사용해 순서를 정한다.
6. 스케쥴러
- 스케쥴러(scheduler) : 어떤 프로세스에게 자원을 할당할지 결정하는 운영체제 커널의 코드
- 스케쥴러에는 장기 스케쥴러와 단기 스케쥴러가 있다.
- 장기 스케쥴러(long term scheduler) : 작업 스케쥴러라고도 부르며, 어떤 프로세스를 준비 큐에 진입시킬지 결정하는 역할을 한다.
- 프로세스가 생성되고 시작 상태를 거쳐 준비 상태가 되기 전에 메모리를 할당할 때 장기 스케쥴러가 관여하게 된다.
- 단기 스케쥴러(short term scheduler) : CPU 스케쥴러라고도 부르며, 준비 상태의 프로세스 중 어떤 프로세스를 다음 번에 실행 상태로 만들 것인지 결정한다. 시분할 시스템에서는 타이머 인터럽트가 발생하면 단기 인터럽트가 발생한다.
- 단기 스케쥴러는 밀리초 정도의 시간 단위로 매우 빈번하게 호출되므로 수행 속도가 충분히 빨라야 하지만, 장기 스케쥴러는 수십 초 내지 수 분 단위로 가끔 호출되기 때문에 상대적으로 속도가 느린 것이 허용된다.
- 장기 스케쥴러는 메모리 할당을 주의해야 하므로 메모리에 동시에 올라가 있는 프로세스의 수(degree of multiprogramming)를 조절하는 역할을 한다.
- 현대의 시분할 시스템용 운영체제에서는 프로세스가 시작 상태가 되면 장기 스케쥴러 없이 곧바로 그 프로세스에 메모리를 할당해 준비 큐에 넣어준다.
- 현대의 시분할 시스템용 운영체제에서는 장기 스케쥴러 대신 중기 스케쥴러를 두는 경우가 많다.
- 중기 스케쥴러(medium term scheduling) : 너무 많은 프로세스에게 메모리를 할당해 시스템의 성능이 저하되는 경우 이를 해결하기 위해 메모리에 적재된 프로세스의 수를 동적으로 조절하기 위해 추가된 스케쥴러
- 너무 많은 프로세스가 메모리에 적재되는 경우 프로세스 당 보유하고 있는 메모리양이 극도로 적어져 스왑 영역에 있는 데이터를 수시로 가져오기 위해 입출력 작업이 자주 발생한다.
- 중기 스케쥴러는 이런 경우 메모리에 올라와 있는 프로세스 중 일부를 선정해 스왑 아웃한다. 즉, 메모리를 통째로 빼앗아 그 내용을 디스크의 스왑 영역에 저장한다.
- 중기 스케쥴러가 스왑 아웃시키는 프로세스 우선 순위는 봉쇄 상태에 있는 프로세스들, 타이머 인터럽트가 발생해 준비 큐로 이동하는 프로세스들 순이다.
- 중기 스케쥴러의 등장으로 프로세스 상태에 중지 상태가 추가되었다.
- 중지(suspended, stopped) : 외부적인 이유로 프로세스의 수행이 정지된 상태. 외부에서 재개시키지 않는 이상 다시 활성화될 수 없어 메모리 자원이 당장 필요하지 않고, 따라서 중지 상태의 프로세스는 메모리를 통째로 빼앗기고 디스크로 스왑 아웃된다.
- 중지 상태는 프로세스가 어떤 상태로 스왑 아웃됐는지에 따라 중지준비 상태와 중지봉쇄 상태로 세분화할 수 있다.
7. 스레드
- CPU 수행 단위로 하나의 프로세스 내 여러 개의 스레드가 존재할 수 있다.
- 스레드의 구성
- PC
- register set
- stack 공간
- 스레드가 프로세스 내 다른 스레드와 공유하는 부분
- code section
- data section
- OS 자원
- 이전에 다루었던 (heavyweight) 프로세스는 하나의 스레드를 가지고 있는 task로 볼 수 있다.
- 스레드의 특징
- 프로세스 내 하나의 스레드가 봉쇄 상태인 동안에도 동일한 task 내의 다른 스레드가 실행되어 빠른 처리가 가능하다.
- 동일한 일을 수행하는 다중 스레드가 협력해 높은 처리율(throughout)과 성능 향상을 얻을 수 있다.
- 병렬성을 높일 수 있다.
- 스레드의 장점
- 응답성 ( ex) 웹 페이지를 불러오는 작업을 하는 경우 한 스레드가 이미지를 불러올 때 다른 스레드가 이미지를 제외한 나머지 텍스트를 표시한다.)
- 자원 공유
- 경제성 : 스레드 생성이나 CPU switching의 overhead가 작다.
- MP(Multiprocessor) 구조의 활용 : 각 스레드는 다른 프로세서(CPU)에서 병렬적으로 실행할 수 있다.
- 스레드의 구현
- kernel thread : 운영체제가 각 프로세스에 여러 스레드가 있는 것을 알고 있어 CPU를 할당할 때 프로세스 내 특정 스레드를 지정한다.
- user thread : 운영체제가 각 프로세스에 여러 스레드가 있는 것을 모르기 때문에 CPU를 할당할 때 특정 프로세스를 지정하고, 해당 프로세스 내에서 CPU를 할당할 스레드를 별도로 지정한다.
7. 프로세스의 생성
- 시스템이 부팅된 후 최초의 프로세스는 운영체제가 직접 생성하지만 그 다음부터는 이미 존재하는 프로세스가 다른 프로세스를 복제 생성한다. 이때 프로세스를 생성한 프로세스를 부모 프로세스라 하고, 새롭게 생성된 프로세스를 자식 프로세스라 한다.
- 자식 프로세스가 먼저 죽고, 이에 대한 처리는 자식을 생성했던 부모 프로세스가 담당하는 방식으로 진행된다.
- 만약 후손들을 여러 단계에 걸쳐 많이 생성한 프로세스가 종료될 경우 그 프로세스가 생성했던 모든 후손 프로세스들을 연쇄적으로 종료시킨 후에야 본인이 종료될 수 있다.
- 생성된 프로세스가 작업을 수행하기 위해 필요한 자원을 획득하는 방법은 운영체제 및 자원의 종류에 따라 상이하다. 어떤 경우에는 운영체제로부터 직접 자원을 할당받을 수도 있고, 또 다른 경우에는 부모 프로세스와 자원을 공유해서 사용할 수도 있다.
- 프로세스가 수행되는 모델에는 부모와 자식이 공존하며 수행되는 모델과 자식이 종료될 때까지 부모가 기다리는 모델이 있다.
- 공존하며 수행되는 모델에서는 자식과 부모가 같이 CPU를 획득하기 위해 경쟁하는 관계가 된다.
- 부모가 자식의 종료를 기다리는 모델에서는 자식 프로세스가 종료될 때까지 봉쇄 상태에 머물러 있다가 자식 프로세스가 종료되면 부모 프로세스가 준비 상태가 되어 다시 CPU를 얻을 권한이 생긴다.
- 부모 프로세스가 자식 프로세스를 생성할 때 자식 프로세스는 부모 프로세스와 별도의 주소 공간을 가지는데, 처음 주소 공간을 생성할 떄에는 부모 프로세스의 주소 공간 내용을 그대로 복사해서 생성한다. 이후 자식 프로세스가 다른 프로그램을 수행할 때 프로그램의 주소 공간을 덮어씌워 실행한다.
- 유닉스의 경우 fork() 시스템 콜을 통해 새로운 프로세스를 만들 수 있다. 이때 부모 프로세스의 내용을 그대로 복제 생성한다. 이후 exec() 시스템 콜을 통해 새로운 프로그램으로 주소 공간을 덮어씌울 수 있다.
- 프로세스 종료는 두 가지로 나눌 수 있다.
- 자발적 종료 : 프로세스가 마지막 명령을 수행한 후 운영체제에게 이를 알려 이루어진다.
- 프로세스는 명령을 모두 수행한 후 프로그램이 끝나는 코드 부분에 exit()라는 시스템 콜을 넣어주도록 되어 있다. 이를 통해 운영체제에게 종료를 통보하면 운영체제는 프로세스로부터 자원을 회수하고 시스템 내에서 이 프로세스를 정리한다.
- 비자발적 종료 : 부모 프로세스가 자식 프로세스의 수행을 강제로 종료시키는 것으로 abort()라는 함수를 통해 이루어진다.
- 강제 종료가 발생하는 경우는 다음과 같다.
- 자식 프로세스가 할당 자원의 한계치를 넘어 많은 양의 자원을 요구할 때
- 자식 프로세스에게 할당된 작업이 더 이상 필요하지 않을 때
- 부모 프로세스가 종료(exit)되는 경우 : 운영체제는 자식 프로세스가 더 이상 수행되지 못하게 하기 때문에 단계적인 종료가 발생한다.
- 사용자 계정으로 서버 컴퓨터에 접속해서 수행시킨 프로그램을 로그아웃 후에도 계속 수행시켜야 하는 경우 로그인 창 아래에 생성된 모든 자식 프로세스들이 종료되기 때문에 해당 프로세스를 로그아웃 후에도 존재하는 시스템 프로세스의 자식으로 이양시키는 절차가 필요하다.
- fork()를 이용해 자식 프로세스를 생성하면 프로세스 식별자를 제외한 모든 값들을 복제해 자식 프로세스를 생성하므로 자식 프로세스는 자신이 자기 자신을 복제했다는 기억을 가지게 된다. 이를 구별하기 위해서는 fork() 함수의 결과값이 0이냐 양수냐에 따라 복제본인지 원본인지를 결정할 수 있다. (결과값이 0이면 복제본이다.)
- exec() 시스템 콜은 프로세스가 지금까지 수행한 상태를 잊어버리고 그 주소 공간을 완전히 새로운 프로그램으로 덮어씌운 후 새로운 프로그램의 첫 부분부터 다시 실행을 시작하도록 하는 시스템 콜이다.
- fork(), exec(), exit() 등은 사용자 프로세스가 직접 수행할 수 없는 특권명령이다.
- wait() 시스템 콜은 자식 프로세스가 종료되기를 기다리며 부모 프로세스가 봉쇄 상태에 머무르도록 할 떄 사용한다.
- 보통 fork() 후에 wait()를 호출해 자식 프로세스가 실행되는 동안 부모 프로세스는 봉쇄 상태에 머무르게 하고, 후에 자식 프로세스가 종료되면 부모를 준비 상태로 변경시켜 작업을 재개할 수 있게 한다. 이러한 방식으로 부모 프로세스와 자식 프로세스 간의 동기화가 가능해진다.
8. 프로세스 간의 협력
- 프로세스는 각자 자신만의 독립적인 주소 공간을 가지고 수행된다. 다른 프로세스의 주소 공간을 참조할 수 없다.
- 그러나 경우에 따라서는 독립적인 프로세스들이 협력할 때 업무의 효율성이 증진될 수 있다.
- 따라서 운영체제는 프로세스 간의 협력 매커니즘을 제공해 하나의 프로세스가 다른 프로세스의 수행에 영향을 미칠 수 있게 한다.
- IPC(Inter-Process Communication) : 하나의 컴퓨터 안에서 실행 중인 서로 다른 프로세스 간에 발생하는 통신
- 이러한 통신에서는 의사소통 기능과 함께 동기화를 보장해줘야 한다. 공유 데이터를 서로 다른 프로세스가 동시에 사용하면 데이터 불일치 문제가 발생하기 때문이다.
- 즉, IPC는 프로세스들 간의 통신과 동기화를 이루기 위한 매커니즘을 의미한다.
- IPC의 대표적인 방법으로는 프로세스 사이에 공유 데이터 사용 여부에 따라 두 가지로 나뉜다.
- 메시지 전달 방식(message passing) : 프로세스 간에 공유 데이터를 사용하지 않고 메시지를 주고받으면서 통신하는 방식
- 두 프로세스가 주소 공간이 달라 메시지 전달은 직접 할 수 없고 대신 커널에 의해 이루어진다. send(message)와 receive(message) 연산을 커널에게 제공받아 프로세스 간의 메시지를 시스템 콜 방식으로 요청해 전달할 수 있다.
- 통신을 원하는 두 프로세스는 커뮤니케이션 링크(communication link)를 생성한 후 send()와 receive()를 이용해 메시지를 주고받는다.
- 메시지의 전송 대상이 어딘지에 따라 다시 직접통신과 간접통신으로 나뉜다.
- 직접 통신(direct communication) : send(P, message), receive(Q, message)와 같이 통신하려는 프로세스의 이름을 명시적으로 표시한다.
- 이를 위한 커뮤니케이션 링크는 자동적으로 생성되고, 하나의 링크는 정확히 한 쌍의 프로세스에게 할당된다. 각 쌍의 프로세스에게는 오직 하나의 링크만 존재하고, 링크는 단방향성일 수 있으나 대부분의 경우 양방향성이다.
- 간접 통신(indirect communication) : 메시지를 메일박스 또는 포트로부터 전달받는다. 각 메일박스에는 고유의 ID가 있으며 메일박스를 공유하는 프로세스들만 서로 통신을 할 수 있다.
- 커뮤니케이션 링크는 프로세스 간에 메일박스를 공유하는 경우에만 생성된다. 하나의 링크가 여러 프로세스들에게 할당될 수 있고 각 프로세스의 쌍은 여러 링크를 공유할 수 있다. 또한 링크는 단방향성 또는 양방향성일 수 있다.
- 간접통신에서는 새로운 메일박스를 생성하는 연산, 메일박스를 통한 메시지의 send()/receive() 연산, 메일박스를 삭제하는 연산 등이 사용될 수 있다.
- 간접통신 방식에서 send(A, message)는 A라는 메일박스에 메시지를 전송하고, receive(A, message)는 A라는 메일박스로부터 메시지를 전달받는다.
- 만약 여러 프로세스가 메일박스를 공유하고 있는 경우 프로세스가 메시지를 보냈을 때 누가 받아야 하는지 결정해야 하는데, 이는 2개의 프로세스에게만 링크를 할당하거나, receive() 연산을 매 시점 하나의 프로세스만 수행하도록 하거나, 누가 메시지를 받았는지 송신자에게 통신해주는 방식이 사용될 수 있다.
- 공유메모리 방식(shared memory) : 프로세스들이 주소 공간의 일부를 공유하는 방식이다. 실제 구현은 프로세스가 독자적인 주소 공간을 가지고 있지만, 이 주소 공간이 물리적 메모리에 매핑될 때 공유 메모리 주소 영역에 대해서는 동일한 물리적 메모리 주소로 매핑되도록 한다.
- 다만 데이터 일관성 문제가 발생할 수 있고 이를 커널이 책임지지 않으므로 프로세스끼리 공유 메모리 접근에 대한 동기화 문제를 해결해야 한다.
출처 : 운영체제와 정보기술의 원리
728x90
'운영체제' 카테고리의 다른 글
6. 메모리 관리 (0) | 2021.04.27 |
---|---|
5. CPU 스케쥴링 (0) | 2021.04.25 |
3. 프로그램의 구조와 실행 (0) | 2021.04.23 |
2. 컴퓨터 시스템의 동작 원리 (0) | 2021.04.22 |
1. 운영체제 개요 (0) | 2021.04.20 |