프로세스

카테고리 없음

2019. 4. 15. 03:47

프로세스

프로세스는 program in execution을 일컫는다. 즉, 메인 메모리에 적재되어 실행중인 프로그램을 프로세스라고 한다.

이러한 의미에 빗대어보면 job, task와 같은 단어들도 범용적으로 프로세스라고 인식할 수 있다.

때로는 프로그램과 혼동할 수도 있는데, 프로그램은 텍스트 섹션(코드 영역)만을 의미하며 이 프로그램이 메인 메모리에 적재되어 스택, 힙, 데이터 영역, 그리고 프로세스 별로 가지고 있는 프로그램 카운터와 같은 자원을 가지고 능동적으로 실행 될 때서야 비로소 프로세스가 되는것이다.

 

프로세스 상태

프로세스 상태

프로세스는 위의 세가지 상태 중 하나를 가진다.

Ready 상태는 프로세스가 CPU에 할당되어 실행되기를 기다리는 상태이고, Running 상태는 프로세스가 CPU에서 실행중인 상태, 그리고 Waiting 상태는 프로세스가 입출력 또는 특정한 이벤트가 끝나기를 기다리는 상태이다.

실행중이던 프로세스가 인터럽트를 만나면 CPU는 인터럽트 서비스를 처리하고 실행중이던 프로세스는 Ready 상태로 가게 된다.

실행중이던 프로세스가 어떠한 입출력이나 이벤트 처리가 필요하다면 이것이 종료될 때까지 Waiting 상태로 가게 되고, 처리가 끝나면 다시 Ready상태로 돌아오게 된다.

Ready 상태에 있던 프로세스가 CPU에 적재되어 실행되려면 Scheduler Dispatch를 통하여 문맥교환 후에 실행되게 된다.

 

PCB ( Process Control Block )

PCB라 불리우는 프로세스 제어 블록은 특정 프로세스와 연관된 여러 정보를 담고 있다. 이를 살펴보면 다음과 같다.

- 프로세스 상태 : 위에서 살펴본 상태에 관한 정보이다.

- 프로그램 카운터 : 해당 프로세스가 다음에 실행할 명령어의 주소를 담고 있다.

- CPU 레지스터 : CPU가 가지고 있던 레지스터 정보를 백업해 둔다.

- CPU 스케쥴링 정보 : 프로세스의 Priority, 스케쥴링 Queue에 대한 포인터 등을 담고 있다.

- 메모리 관리 정보 : 메모리의 base register, limit register, 메모리 시스템에 대한 정보 등을 담고 있다.

- Account 정보 : 현재 프로세스가 CPU 자원을 사용하는 정도에 대한 정보, pid 등을 담고 있다.

- 입출력 상태 정보 : 현재 프로세스에게 할당된 입출력 장치나 파일들의 목록과 같은 정보를 담고 있다.

 

운영체제의 스케쥴러가 CPU에 여러개의 프로세스들 중 하나를 적재시킬 때, PCB를 사용한다. 예를 들어 두 개의 프로세스 P0와 P1가 있고, 현재 P0가 CPU에 할당되어 실행중이라고 하자. 그럼 다음과 같은 순서로 프로세스 전환이 일어난다.

1. 인터럽트 또는 시스템 콜에 의해 P1으로의 프로세스 전환 요청

2. CPU의 상태를 P0의 PCB에 백업

3. P1의 PCB 정보를 CPU에 복원

4. P1 실행

5. 인터럽트 또는 시스템 콜에 의해 P0로의 프로세스 전환 요청

6. CPU의 상태를 P1의 PCB에 백업

7. P0의 PCB 정보를 CPU에 복원

8. P0 실행

...

 

이렇게 PCB를 백업하고 복구하는 과정을 문맥 교환(Cotext Switch)이라고 하는데, 문맥 교환 중에는 CPU는 실질적인 프로세스의 연산을 수행하지 않으므로 문맥 교환에 소모되는 시간은 분명 오버헤드(Overhead)이다. 이 오버헤드는 하드웨어의 지원 수준에 따라서 달라진다. 예를 들어, 하드웨어에서 많은 수의 레지스터를 지원하고 이들 중 일부만 프로세스가 사용한다면, 나머지 레지스터들은 PCB를 저장하기 위해 메인메모리 처럼 사용 가능하므로 오버헤드를 많이 줄일 수 있다.

 

스케쥴링 큐 ( Scheduling Queue )

위에서 프로세스의 상태에는 ready, running, wait 상태가 있는것을 살펴보았다. 이 중 ready와 wait 상태에 있는 프로세스들은 특정 큐에 들어가게 된다.

CPU에게 할당되어 실행되길 기다리는 ready 상태를 가지는 프로세스들의 PCB들이 들어가 있는 큐를 레디 큐(Ready Queue)라고 하고, 실행 중이던 프로세스가 I/O의 요청을 하고 마무리 될때까지 기다리게 되는 경우 해당 프로세스의 PCB가 기다리게 되는 큐를 디바이스 큐(Device Queue) 또는 I/O 큐라고 한다. 각 큐는 머리와 꼬리를 가지고 있는 헤더를 가지고 있는 연결 리스트로 구현되어 있다.

 

Long Term, Medium Term, Short Term 스케쥴러

스케쥴러에는 세 가지가 있다. 그 중 롱 텀과 숏 텀 스케쥴러에 대해 먼저 알아보자면,

Long Term Scheduler : 어떤 프로그램을 Disk에서 Main Memory로 적재해야 하는지 결정하는 스케쥴러

Short Term Scheduler : 어떤 프로세스를 Main Memory에서 CPU로 적재해야 하는지 결정하는 스케쥴러

이들 스케쥴러는 프로세스가 I/O에 포커스 되어있는지 아니면 CPU 연산에 포커스 되어있는지에 따라 스케쥴링의 빈도가 커지거나 작아지게 된다. 어떤 시스템에서는 롱 텀 스케쥴러가 없으며, 이를 대체하기 위해 Swapping을 지원하는 Medium Term 스케쥴러를 채택한다.

세 가지 스케쥴러의 동작방식

프로세스 생성 ( Process Creation )

일반적으로 프로세스는 다른 프로세스로부터 생성되며, 생성하는 프로세스를 부모 프로세스(parent process), 생성되는 프로세스를 자식 프로세스(child process)라고 한다. 자식 프로세스는 또다른 자식 프로세스를 생성할 수 있으므로, 모든 프로세스는 UNIX 시스템을 예로 들었을 때 init 프로세스를 루트(root)로 하는 트리(tree) 구조로 나타낼 수 있다. 각각의 프로세스는 고유의 프로세스 식별자인 프로세스 아이디(pid)를 가진다.

 

프로세스는 연산을 수행하기 위하여 CPU 시간, 메모리, 파일, 입출력 장치 등의 자원(Resource)를 필요로 하는데, 자식 프로세스는 이러한 자원을 운영체제로부터 직접 얻거나 부모 프로세스로부터 물려받을 수 있다. 모든 자원을 공유할수도 있고, 일부를 공유하거나, 아예 공유하지 않을 수도 있다.

 

부모 프로세스로부터 실행된 자식 프로세스는 부모 프로세스와 동시에 실행될 수도 있고, 부모 프로세스가 자식 프로세스가 종료될 때까지 기다리는 방식으로 직렬로 수행될수도 있다.

 

UNIX 시스템에서는 fork() 시스템 콜로 자식 프로세스를 생성하고, exec() 시스템 콜로 현재 프로세스의 메모리 공간(코드, 데이터, 스택 영역)을 다른 프로그램으로 대체할 수 있으며, wait() 시스템 콜로 자식 프로세스의 실행 종료를 기다릴 수 있다.

 

프로세스 종료 ( Process Termination )

생성된 프로세스는 스스로 종료하거나, 자신의 부모 프로세스로부터 종료될 수 있다.

UNIX 시스템에서, 프로세스는 자신의 프로세스를 exit() 시스템 콜에 의해 종료할 수 있으며, 부모 프로세스는 wait() 시스템 콜에 의해 자식 프로세스가 종료되기를 기다릴 수 있다.

자식 프로세스가 종료되었는데 부모 프로세스는 종료되지 않았고 자식 프로세스를 기다리는 wait()과 같은 시스템 콜을 호출하지 않는 경우 이 자식 프로세스는 좀비 프로세스(zombie process)라 하고,

자식 프로세스는 동일하게 종료되었지만 부모 프로세스가 자식 프로세스를 기다리지 않은 상태에서 종료된 경우 이때의 자식 프로세스를 고아 프로세스(orphan process)라고 한다.

 

프로세스 간 통신 ( Interprocess Communication )

서로 협력적인 프로세스들 간에 정보 공유, 계산 가속화, 모듈성, 편의성 등의 이유로 데이터와 정보를 교환할 수 있는 통신이 필요하다. 이를 프로세스 간 통신이라고 하며, 크게 두 가지의 방법이 있다.

 

1. 공유 메모리(shared memory) 방식 : 프로세스들 간에 공유되는 메모리 영역이 구축되고, 이 메모리 영역을 통해 통신한다.

2. 메세지 전달(message passing) 방식 : 프로세스들 간에 메세지 큐(message queue)를 통해 메세지를 주고받으며 통신한다.

 

공유 메모리 시스템 ( Shared-Memory System )

공유 메모리 시스템의 대표적 패러다임으로는 Producer - Consumer 패러다임이 존재한다. 이는 생산자가 공유 메모리에 정보를 채워 넣고 소비자가 정보를 소모하는 방식이다. 이 때 공유 메모리에 두 가지 형태의 버퍼가 사용된다.

 

1. 무한 버퍼 (unbounded buffer) : Producer는 버퍼의 크기에 관계없이 항상 새로운 정보를 생성할 수 있다.

2. 유한 버퍼 (bounded buffer) : Producer는 버퍼의 크기가 고정되어 버퍼가 가득차는 경우 대기해야만 한다.

 

메세지 전달 시스템 ( Message-Passing System )

메세지 전달 방식은 공유 메모리 시스템처럼 동일한 메모리 공간을 공유하지 않고도 프로세스간의 통신을 하고 동기화가 가능한 방식이다. 메세지 전달 방식에서 두 프로세스 간에 통신이 일어나기 위해서는 별도의 링크(link)가 생성되어야 하고, 이 링크는 다양한 방법으로 연결될 수 있다.

 

1. 메세지를 보내고 받는 프로세스를 지정하는 방식 : 직접 통신

2. 메일박스(mailbox)를 사용하여 메세지를 주고받는 방식 : 간접 통신

 

이 때 동기화(Synchronization)는 중요한 문제다. 동기화 기법으로는 봉쇄형, 비 봉쇄형이 있다.

 

1. Blocking Send : 메세지가 수신될 때까지 보내지 않는다.

2. Blocking Receive : 메세지가 발송될 때까지 수신하지 않는다.

3. Non-Blocking Send : 메세지 수신여부에 관계없이 보낸다.

4. Non-Blocking Receive : 메세지 발송여부에 관계없이 수신한다. 발송된 메세지가 없는 경우 NULL을 수신한다.

특히나 1과 2가 동시에 만족될 때 랑데부(randezvous)라고 한다.

 

메세지 큐의 버퍼 크기도 세 가지 경우로 나눌 수 있다.

 

1. zero capacity : randezvous 상황이 연출된다.

2. bounded capacity : 버퍼가 가득 차게 되면 송신자는 blocking send모드가 되어야 한다.

3. unbounded capacity : 현재 버퍼의 항목개수에 관계없이 송신자는 지속적으로 송신이 가능하다.

 

참조

ABRAHAM SILBERSCHATZ, PETER BAER GALVIN, GREG GAGNE / 운영체제 / (주)교보문고 / 2018년