article thumbnail image
Published 2023. 3. 29. 16:18

Process Concept

Program이란, Disk 상에 존재하는 "실행 가능한 파일"을 의미하며, 

이들이 Memory(RAM)에 Load 되었을 때, 이를 Process라고 한다.

또한, 작업의 단위를 의미한다. 

 

Address Space

Process가 만들어지면 OS로부터 "Address Space"라고 불리는 고유한 메모리 영역을 할당 받는다.

 

Address Space는 4가지 영역으로 구분할 수 있다.

  • Text Section : program의 코드들이 기계어로 저장되어 있는 영역이다. CPU에 의해 하나씩 처리된다.
  • Data Section : Global 변수, Static 변수가 저장된다. 프로그램 시작과 함께 할당되어 종료가 되면 소멸한다.
  • Stack Section : 함수의 Local 변수, 파라미터, return address가 저장되어 있다. 함수의 호출과 동시에 할당이 되며, 함수의 수행이 끝나면 소멸된다.
  • Heap Section : 런타임에 동적으로 할당되는 영역이다. 

Program은 디스크에 저장된 실행 가능한 파일이며, Passive(수동적인) Entity라고 불리며,

Process는 resource를 할당받아 수행할 수 있는 Active(능동적인) Entity라고 불린다.

 

Process State

Process는 다음과 같은 state를 갖는다. 

  • New : Process가 생성되는 상태
  • Running : Process의 code section의 명령어들이 CPU에서 실행되고 있는 상태
  • Waiting(Blocked, Sleep) : Process가 어떤 Event를 기다리고 있는 상태
  • Ready : Process가 CPU에 할당받아 수행되길 기다리고 있는 상태
  • Terminated : 프로세스가 종료된 상태

 

PCB (Process Control Block)

Process가 생성이 되면,

OS는 Process의 정보를 저장하는 자료구조 PCB (Process Control Block)를 생성한다.

 

PCB는 Kernel Space에 저장된다. 

Memory(RAM)은 논리적으로 User Space와 Kernel Space로 나눌 수 있다. 
Kernel Space는 OS를 위해 할당된 공간으로, User가 접근할 수 없다.

PCB는 여러 attribute로 구분된다. 

  • Process ID : Process가 생성되면 OS는 고유한 ID를 부여한다.
  • Process State : New, Ready, Running, ...
  • Program Counter : Code Section에 저장된 명령어 중 다음에 수행해야 할 명령어의 주소를 가리킨다.
  • CPU Register : Process가 Interrupt 이후 작업을 재개하기 위해 참조하는 CPU Register 값
  • CPU Scheduling Information : Process Priority 등 스케쥴링 정보 
  • Memory-Management Information : Page Table, Segment Table과 같은 정보를 포함한다.
  • Accounting Information : 몇 개의 CPU를 사용했는가 등의 정보를 포함한다.
  • I/O Status Information : Open files와 할당된 I/O device에 대한 정보들 포함한다.

 

Process Scheduling

하나의 CPU는 하나의 Process 혹은 Task만 수행이 가능하다.

따라서, OS는 CPU에 적절한 Process를 할당하여야 한다. 

 

이는 CPU Schedular에 의해 수행되며,

어떤 CPU에 어떤 Process를 할당할지 결정하는 작업Process Scheduling이라고 한다.

 

Shceduling Queue

Process가 시스템에 들어오면 "Job Queue"에 위치하게 되며, 시스템의 모든 Process가 위치해 있다.

 

Ready 상태의 Proess들은 "Ready Queue"에 위치하게 되며, 

특정 I/O Device(프린터, 모니터 .. )를 대기하는 Process들"Device Queue"에 위치하게 된다. 

 

 

Context Switching

Time-Shared System (Multi-Tasking)이란, 

Task 혹은 Process를 번갈아 가며 수행하여, 유저에게 동시에 수행하는 것처럼 느끼도록 제공한다.

 

Process Scheduling을 통해 Switching할 Process를 선택하는 것도 중요하지만, 

수행하고 있던 Process의 Context를 저장하고, Switching할 Process의 Context를 Load하는 것도 중요하다.

Process의 Context는 PCB에 저장되며, Load 할 때는 Switching Process의 PCB에서 이를 복구한다.

즉, Context Switching이란, 

수행하고 있던 Process의 Context를 PCB에 저장하고, 

Switching할 Process의 Context를 PCB로부터 Load하는 작업을 의미한다.

 

Context Swithcing을 진행하는 동안, 

시스템은 어떠한 Useful한 작업을 진행할 수 없기 때문에, 이는 약간의 Overhead가 발생된다.

 

 

Operations on Processes

Process Creation

Process는 다른 Process를 생성할 수 있다. 

생성한 Process를 Parent Process라 부르고, 생성된 Process를 Child Process라 부른다.

이는 결과적으로 Process tree를 생성한다.

위의 그림에서 pid는 Process ID를 의미하며, OS에 의해 할당되어 Process마다 고유한 정수 값을 가진다.

 

Child Process는 수행하기 위해 Resource가 필요한데, 

Parent Process의 Resource를 전부 혹은 일부만 공유하거나, 

공유하지 않고 OS로부터 할당받는다.

 

또한, Address Space의 경우에는 text 영역은 Parent Process와 공유하고, 

나머지 data, heap, stack 영역은 별도로 할당되어, 부모의 값이 복사된다.

(즉, stack 영역의 Local 변수가 이름은 같아도, 다른 값을 가질 수 있다.)

PCB도 따로 생성되지만, Parent Process의 PCB를 복사한다.

UNIX의 경우에는 fork() System call을 통해 Child Process를 생성한다.

pid = fork();

// child
if(pid == 0) { ... }

// parent
else if (pid > 0) { ... }

// pid 음수인 경우 에러
else { ... }

fork()의 경우 process ID를 반환하는데, 

Child Process에게는 0을 반환하고,

Parent Process에겐 Child Process의 Process ID를 반환한다.

Parent Process와 Child Process는 동시에 실행된다. 

 

또한, exec 계열의 system call은 프로그램을 실행한다. 

따라서, 자식 프로세스에서 exec 계열의 system call을 호출한다면, 

Address Space가 새로운 프로그램을 위한 것으로 대체된다.

 

따라서, fork를 통해 생성된 Child Process는 Address Space, PCB 등을 Parent Process로부터 복사되지만, 

exec 계열의 system call을 Child Process에서 사용하면, Address Space에 새로운 프로그램이 load된다.

 

Process Termination

Process는 마지막 명령어를 끝내고, exit() system call을 통해 OS에 Process 삭제 요청을 할 수 있다. 

Child Process는 Parent에게 status 값을 리턴하고, OS에 의해 할당된 모든 Resource들이 반납된다. 

Parent Process는 wait() system call을 통해 Child Process의 종료를 기다릴 수 있다.

pid = wait(&status);

또한, 이를 통해 Child Process의 pid와 exit status를 알 수 있다. 

 

만약, Parent Process가 Child Process를 wait하지 않는다면,

(wait의 수행보다 Child Process의 exit이 빠른 경우)

Child Process의 일부 Resource는 회수되지 못하고, OS에 남아있게 된다.

이때, 이 Child Process를 "zombie Process"라고 한다. 

 

또한, Parent Process가 wait()를 호출하지 않고 종료해 버린 경우,

Child Process는 "Orphan(고아) Process"라고 한다. 

Linux와 Unix에서는 Orphan process의 부모를 최상위 Process(init)으로 지정함으로써 이를 해결한다.  

 

abort

Parent Process는 다음과 같을 때, Child Process의 수행을 종료한다.

  • Child Process가 할당된 resource를 초과하여 사용할 경우
  • Child Process에 할당된 작업이 더 이상 필요 없는 경우
  • OS 자체적으로 Parent Process가 종료되었을 때, Child Process가 홀로 수행하는 것을 허용하지 않는 경우.

3번째 경우에는 연쇄적으로 종료가 되며 이를 "cascading termination"이라 부른다.

 

 

Interprocess Communication(IPC)

Process들은 Independent하게 동작할 수도 있지만, 서로 Cooperative (상호 협력적)하게 동작할 수도 있다. 

상호 협력적인 Process들은 Subtask로 나누어 실행을 통해 task를 빠르게 수행할 수 있으며, 모듈화, 편의성 여러 장점이 존재한다. 

 

상호 협력적인 Process들 간의 정보 공유를 위해 2가지 IPC(Interprocess Communication)기법이 있다. 

  • Shared Memory
  • Message Passing 

 

Producer-Consumer Problem 

상호 협력적인 프로세스 관계에선, 

정보 혹은 데이터를 생산하는 Producer(생산자) Process,

정보 혹은 데이터를 소비하는 Consumer(소비자) Process라 한다. 

 

"Producer-Consumer Problem"이란, 

동기화와 관련된 문제로 생산하는 속도와 소비하는 속도가 차이가 날 때 발생한다. 

예를 들어 생산하는 속도가 소비하는 속도보다 빠른 경우, 생산되는 데이터가 사용되지 못하는 상황이 발생한다.  

 

이를 해결하기 위해, 생산자와 소비자 사이에 버퍼(buffer)라는 메모리를 위치한다.

크기가 유한한 버퍼를 "Bounded Buffer"라 하며, 

반대의 경우는 "Unbounded Buffer"라 한다.

 

 현실적으로 버퍼는 메모리 상에 위치하기 때문에, Bounded Buffer이다. 

즉, 크기가 유한하기 때문에, 버퍼를 위치한다해도 문제가 발생하게 된다.

(버퍼가 다 차게되면, 기존의 버퍼를 덮어써야 하기 때문에, 결국엔 생상된 데이터가 사용되지 못하는 상황 발생)

따라서, 이를 Bounded-Buffer문제라고도 한다.

 

이는 추가적인 스케쥴링을 통해 해결하여야 한다.

 

 

Shared Memory

IPC방식 중 "Shared Memory"는 Process 간에 일부 Address Space를 공유하는 방식이다.

통신하는 Process들은 OS에 의해 Shared Memory 영역을 할당받으며,

이 Shared Memory 영역을 통해 정보를 주고받는다.

Shared Memory 방식에서 정보를 주고받을 때,

Kernel을 거치기 않기에 속도가 빠른 편이다. 

 

하지만, 여러 Process들이 동시에 Shared Memory영역에 접근할 경우에 대한 처리는 프로그래머가 따로 구현해주어야 한다.

 

 

Message Passing

Message Passing 방식은 Address Space를 공유하지 않고,

Kernel을 통해 Message를 주고받는다.

생산자 Process는 send system call로 Kernel을 통해 Message를 전달하며, 

소비자 Process는 receive system call로 Kernel을 통해 Message를 수신한다.

 

Message Passing 방식은 Context Switching이 발생하고, 커널을 거치지 때문에 

Shared Memory에 비해 느리다.

 

반면, 커널이 Message Passing을 위한 기본적인 기능을 제공하기 때문에, 구현이 쉽다.

 

Message Passing 방식은 통신할 Process 간의 Communication Link를 설정하고

send, receive System Call을 통해 Message를 주고받는다.

 

이 Communication Link는 H/W Bus, network와 같은 물리적인 방법으로 설정도 가능하지만, 

Direct/Indirect, Sync/Async와 같은 논리적인 방법으로도 설정이 가능하다. 

 

이 중 논리적으로 Communication Link를 설정하는 Direct, Indirect 방식에 대해 알아보자.

 

Direct Communication

Communication Link를 통신하고자 하는 Process 쌍들 사이에 생성한다. 

이는 서로 Process의 이름을 알아야 한다. 

  • send(P, message) : P process에게 message를 커널을 통해 전달한다.
  • receive(Q, message) : Q process에게 message를 커널을 통해 수신한다.

이는 Process의 이름이 변경되면, 연결되어 있는 모든 Process에서 변경이 이루어져야 한다는 단점이 있다. 

 

Indirect Communication

Communication Link를 Mailbox를 공유하고 있는 Process사이에 생성한다. 

Mailbox를 생성하면, Mailbox는 unique한 ID를 가지게 되며, 이를 통해 Process는 정보를 주고받는다. 

  • send(M, message) : Mailbox M으로 message를 전달한다.
  • receive(M, message) : Mailbox M에서 message를 수신한다.

 

Synchronization

Message Passing에서 동기화 문제는 "Blocking", "Non-Blocking" 방식을 통해 해결한다.

 

Blocking 방식은 동기식(Synchronous)으로 간주된다.

  • Blocking Send : 소비자가 message를 받을 때까지 생산자는 Block 된다.
  • Blocking Receive : 소비자는 메시지를 받을 때까지 Block 된다. 

 

Non-Blocking 방식은 비동기식(Asynchronous)으로 간주된다. 

  • Non-Blocking Send : 생산자는 message를 보내고 작업을 계속 진행한다. 
  • Non-Blocking Receive : 소비자는 valid message 혹은 null message를 받는다.

 

 

Reference

Abraham Silberschatz, Peter B. Galvin, Greg Gagne의 『Operating System Concept 9th

'CS > Operating System' 카테고리의 다른 글

[OS] Synchronization  (0) 2023.04.06
[OS] CPU Scheduling  (0) 2023.04.05
[OS] Threads  (0) 2023.04.02
[OS] Operating System Structures  (1) 2023.03.20
[OS] Operating System  (0) 2023.03.12
복사했습니다!