[OS] 프로세스 스케줄링
쉰 네 번째 포스팅
안녕하세요! 쉰 네 번째 포스팅으로 찾아뵙게 되어 반갑습니다!♥
오늘의 포스팅 내용은 프로세스 스케줄링에 관한 내용입니다.
자세한 내용을 알아보러 갑시다❗️
[Boongranii] Here We Go 🔥
1️⃣ 프로세스란?
📀 프로세스 개념
프로세스는 실행 중인 프로그램을 말한다. 일련의 명령어들이 메모리에 적재되어 실행되는 상태를 말한다.
프로세스는 현대의 시분할 시스템에서 작업의 기본 단위로 사용된다.
프로세스의 구성 요소
- 텍스트 섹션 : 프로그램의 코드 부분
- 프로그램 카운터 : 다음에 실행할 명령어의 주소를 가리키는 역할
- 스택 : 지역 변수 및 함수 호출 정보를 저장
- 데이터 섹션 : 전역 변수 및 정적 변수를 저장
- 힙 : 동적으로 할당된 메모리 관리
프로세스의 종류
- I/O 바운드 프로세스 : 연산보다는 입출력 작업에 더 많은 시간을 소비하는 프로세스이다. 예를 들어, 파일을 읽고 쓰는 등의 작업을 수행한다.
- CPU 바운드 프로세스 : 연산에 더 많은 시간을 소비하는 프로세스이다. 계산이 많이 필요한 작업을 수행한다.
프로세스는 현대 컴퓨팅에서 중요한 개념으로, 시스템의 성능 및 작업 효율성을 이해하는 데 필수적이다.
📀 프로세스 상태
프로세스 상태(Process State)는 프로세스가 시스템에서 수행되는 동안 거치는 다양한 상태를 나타낸다.
- New
- 프로세스가 생성되었지만 아직 시스템에 적재되지 않은 상태다. 이 단계에서는 프로세스가 초기화되고 자원이 할당되기를 기다린다.
- Ready
- 프로세스가 실행을 기다리는 상태이다. 모든 준비가 완료되었고 CPU를 할당받을 준비가 된 상태를 말한다.
- Running
- CPU를 점유하고 명령어를 실행 중인 상태이다. 실행 중인 프로세스는 하드웨어에서 명령을 실행하고 작업을 수행한다.
- Waiting
- 프로세스가 어떤 이벤트가 발생하기를 기다리는 상태다. 예를 들어, 입출력 완료를 기다리는 등의 이벤트를 기다리는 상태다.
- Terminated
- 프로세스가 실행을 완료하고 시스템에서 제거된 상태다. 이 단계에서는 프로세스의 자원이 해제되고 메모리에서 제거된다.
- Interrupt
- 외부 이벤트가 발생하여 현재 실행 중인 프로세스를 일시적으로 중단시키는 상태다. 이벤트 발생 후, 인터럽트 처리기가 실행되어 해당 인터럽트에 대한 처리를 수행한다.
프로세스가 시스템에서 수행되는 동안 거치는 주요한 상태들을 나타낸다.
"Scheduler dispatch"
는 스케줄러가 프로세스를 선택하여 CPU에 할당하는 과정을 나타낸다.
"I/O or event wait"
는 입출력이나 이벤트 완료를 기다리는 상태를 나타낸다.
"I/O or event completion"
은 입출력이나 이벤트가 완료되었음을 나타낸다.
"admitted"
는 새로운 프로세스가 시스템에 입장하여 준비 상태로 전환되기를 기다리는 상태를 나타낸다.
📀 PCB(Process Control Block)
프로세스와 관련된 정보이다. 여러 프로세스와 관련된 정보들이 어떻게 관리되는지를 설명하고 있다.
- Process state : 프로세스의 현재 상태다. 실행 중인지, 대기 중인지를 나타낸다.
- Program counter : 다음 실행 명령어의 주소를 가리키는 역할을 한다.
- CPU registers : 프로세스에 대한 모든 레지스터의 내용을 포함한다. 이는 프로세스가 실행되는 동안 필요한 모든 레지스터 값들을 포함한다.
- CPU Scheduling Information : 프로세스 CPU 할당 우선순위, 스케줄링 큐 포인터 등과 같은 정보를 포함한다.
- 메모리 관리 정보 : 프로세스에 할당된 메모리와 관련된 정보를 포함한다.
- 회계 정보 : cpu 사용량, 시작 이후 경과 시간, 시간 제한 등과 같은 정보를 포함한다.
- I/O 상태 정보 : 프로세스에 할당된 I/O 디바이스 및 열려 있는 파일 목록과 같은 정보를 포함한다.
이러한 정보들은 각 프로세스의 상태 및 동작을 관리하기 위해 필요하다. 이러한 정보는 프로세스 제어 블록(PCB)라고 하는 자료 구조에 저장된다. PCB는 프로세스에 대한 정보를 저장하고 관리하는 데 사용된다. 그러므로 각 프로세스에 대한 정보의 저장소 역할을 한다.
📀 Switch from process to process
프로세스 간 스위칭은 운영 체제가 다중 프로세스를 관리하고 각각의 프로세스가 CPU를 공유할 수 있도록 하는 중요한 작업이다. 이 때 PCB는 핵심적인 역할을 한다.
- 프로세스 상태 전환
- PCB에는 각 프로세스의 상태가 포함된다. p0이 실행중이고 p1이 대기 중인 경우, PCB에는 이러한 상태 정보가 저장된다.
- 프로세스 context 교환
- CPU는 한 번에 하나의 프로세스만 실행 가능하다. 따라서 실행 중인 프로세스가 다른 프로세스로 전환될 때는 context 스위칭이 필요하다. 이 때 PCB가 사용됨.
- 현재 실행 중인 프로세스의 상태, 프로그램 카운터, CPU 레지스터 등의 정보는 해당 프로세스의 PCB에 저장된다.
- 운영체제는 PCB에 저장된 정보를 사용하여 다음으로 실행할 프로세스의 상태를 복원함.
- 프로세스 실행 재개
- 대기 중이던 다음 프로세스의 PCB에서 필요한 정보를 로드하여 CPU가 해당 프로세스를 실행.
- 이 때 PCB에 저장된 프로그램 카운터 값을 사용하여 해당 프로세스가 중단된 시점부터 실행을 재개함.
- PCB의 중요성
- PCB는 프로세스 간 전환을 가능하게 하는 핵심적인 데이터 구조이다. 각 프로세스의 상태 및 실행에 필요한 정보를 저장하고 관리함.
- PCB를 통해 운영체제는 다중 프로세스를 효율적으로 관리하고 각 프로세스가 필요한 리소스에 접근할 수 있도록 함.
- PCB는 프로세스 간 전환 시점에서 context를 저장하고 복원하는 데 사용되어 실행 중인 프로세스의 상태를 정확하게 유지함.
이렇게 PCB를 통해 프로세스 간 전환은 운영체제가 다중 프로세스를 효율적으로 관리하고 CPU를 공유할 수 있도록 한다.
2️⃣ 프로세스 스케줄링
💿 Process Scheduling
- CPU 사용 최대화, 빠른 프로세스 전환
- 시간 공유를 위해 CPU 사용을 최대화하고, 프로세스를 빠르게 CPU로 전환한다. 이는 다중 작업 환경에서 CPU를 효율적으로 활용하여 여러 프로세스가 동시에 실행되도록 한다.
- 다음 실행할 프로세스를 선택
- 프로세스 스케줄러는 CPU에서 실행할 다음 프로세스를 선택한다. 이는 시스템에 여러 프로세스가 있을 때 어떤 프로세스가 CPU를 사용할지 결정하는 중요한 역할을 함.
- 프로세스 스케줄링 큐 유지
- 프로세스 스케줄러는 프로세스를 관리하기 위해 여러 종류의 큐를 유지한다.
- 작업 큐(Job queue) : 시스템 내 모든 프로세스의 집합이다. 이 큐에는 메모리에 있는지 여부와 상관없이 모든 프로세스가 포함된다.
- 준비 큐(Ready queue) : 메인 메모리에 상주하고 있으며 실행을 기다리고 있는 모든 프로세스의 집합이다. CPU에서 실행될 준비가 되어있음.
- 장치 큐(Device queue) : 입출력 장치를 기다리는 프로세스의 집합. 파일을 읽거나 쓰기 위해 디스크 I/O를 기다리는 프로세스가 여기에 속함.
- 프로세스 스케줄러는 프로세스를 관리하기 위해 여러 종류의 큐를 유지한다.
- 프로세스 간 큐 이동
- 프로세스들은 다양한 큐 간 이동 가능하다. 입출력 작업을 수행하기 위해 준비큐에서 장치큐로 이동할 수 있다. 이런 이동은 각 프로세스의 상태 변화나 시스템 리소스의 활용을 최적화하기 위해 이루어진다.
프로세스 스케줄링은 시스템의 효율성과 성능을 관리하는 핵심적인 부분으로, CPU 및 기타 시스템 리소스의 효율적인 사용을 보장한다.
💿 Scheduler
- Short-term Scheduler(단기 스케줄러)
- 다음에 실행할 프로세스를 선택하고 CPU를 할당하는 역할을 한다.
- 시스템에서 유일한 스케줄러인 경우도 있음.
- 매우 빈번하게(밀리초 단위) 호출되므로 실행이 빨라야 한다.
- 주로 프로세스의 실행 시간을 최적화하기 위해 사용한다.
- Long-term Scheduler(장기 스케줄러)
- Ready queue로 가져올 프로세스를 선택한다.
- 단기 스케줄러와는 달리 드물게 호출된다.
- 다중 프로그래밍의 정도를 제어한다.
- 좋은 프로세스의 조합을 유지하기 위해 노력한다.
- Mid-term Scheduler
- 다중 프로그래밍의 정도를 줄여야할 때 추가될 수 있다.
- 이는 메모리에 있는 프로세스의 수를 줄여야할 때 사용된다.
- 중간 스케줄러의 주요 기능은 메모리에서 프로세스를 제거하고 디스크에 저장한 다음 나중에 다시 메모리로 가져와서 실행을 계속할 수 있도록 하는 것임. -> 이러한 과정이 스와핑이라 함.
Swap out
- 중간 스케줄러는 메모리에서 우선순위가 낮은 프로세스를 선택하여 디스크에 저장한다.
- 프로세스의 현재 상태는 디스크의 스왑 공간에 저장된다.
- 이후에 다시 실행될 때를 대비하여 프로세스의 상태 정보도 저장한다.
Swap in
- 중간 스케줄러는 디스크에서
swap out
된 프로세스 중 하나를 선택하여 메모리로 다시 가져온다. - 프로세스의 상태 정보와 메모리 내용을 메모리로 복원한다.
- 이후 해당 프로세스는 cpu에서 실행 재개한다.
이렇게 스와핑을 통해 중간 스케줄러는 시스템의 메모리를 효율적으로 관리하고, 필요에 따라 다중 프로그래밍의 정도를 동적으로 조절 가능하다.
이는 시스템의 성능과 사용 가능한 자원을 최적화하는 데 도움이 된다.
3️⃣ Operations on Process
프로세스와 관련된 주요 작업은 다음의 내용이 있다.
- 프로세스 생성(Process Creation)
- 새로운 프로세스를 생성한다.
- 프로세스 종료(Process Termination)
- 프로세스의 실행을 종료하고 시스템에서 제거한다.
- 우선순위 설정/얻기(Get/Set Priority)
- 프로세스의 우선순위를 설정하거나 현재 우선순위를 확인한다.
- 프로세스 ID 얻기(Get ID)
- 프로세스의 고유 식별자를 얻는다.
- 프로세스 제어 블록 얻기(Get PCB)
- 현재 실행 중인 프로세스의 정보를 포함한 프로세스 제어블록을 얻는다.
💾 Process Creation
Process Creation은 새로운 프로세스를 시스템에 만들고 실행할 때 발생하는 작업이다.
- 프로세스 생성 요청
- 부모 프로세스가 자식 프로세스를 생성하는 요청을 보낸다. 부모 프로세스는 보통
fork()
,spawn()
또는createProcess()
와 같은 시스템 호출을 사용하여 이를 수행한다.
- 부모 프로세스가 자식 프로세스를 생성하는 요청을 보낸다. 부모 프로세스는 보통
- 새로운 프로세스의 공간 할당
- 새로운 프로세스를 위한 메모리 공간을 할당한다. 이는 코드, 데이터, 스택 및 힙과 같은 섹션들을 포함한다.
- 프로세스 초기화
- 새로운 프로세스의 초기 상태를 설정한다. 이는 프로세스의 시작 주소를 설정하고, 인자를 전달하고, 필요한 리소스를 초기화하는 등의 작업을 포함한다.
- 부모-자식 관계 설정
- 새로운 프로세스는 보통 부모 프로세스의 하위 프로세스로 설정된다. 부모 프로세스는 자식 프로세스의 생성과 실행을 관리한다.
- 프로세스 스케줄링
- 새로운 프로세스는 Ready queue에 추가되어 다음에 실행될 수 있도록 대기한다. 시스템의 스케줄러는 이후 실행될 프로세스를 선택한다.
프로세스 생성은 계층적 구조를 형성하는 데 사용될 수 있다. 부모 프로세스가 자식 프로세스를 생성하고, 그 자식 프로세스가 또 다른 자식 프로세스를 생성하는 식으로 계속된다. 이런 방식으로 프로세스들은 트리 구조를 형성한다.
🎥 UNIX example
UNIX 환경에서 fork()
와 exec()
시스템 호출은 프로세스 생성과 관련된 기능을 수행한다.
- fork() 시스템 호출
fork()
시스템 호출은 새로운 프로세스를 생성한다. 부모 프로세스는 자식 프로세스를 생성하고, 이를 통해 프로세스 트리가 형성된다.fork()
호출 시에는 현재 실행 중인 프로세스의 상태를 그대로 복사하여 자식 프로세스를 생성한다. 이때, 부모 프로세스의 모든 정보(코드, 데이터, 스택 등)가 자식 프로세스로 복제된다.fork()
호출 이후에는 부모 프로세스와 자식 프로세스가 동일한 프로그램 코드를 실행하게 된다.
- exec() 시스템 호출
exec()
시스템 호출은fork()
호출 후에 새로운 프로그램을 실행하기 위해 사용된다.exec()
호출은 현재 프로세스의 메모리 공간을 새로운 프로그램의 내용으로 덮어 씌운다. 이때, 새로운 프로그램의 코드, 데이터, 스택 등이 메모리에 로드된다.exec()
호출 이후에는 이전의 프로세스 상태나 코드는 모두 사라지고, 새로운 프로그램이 실행된다.
이러한 fork()
와 exec()
시스템 호출은 UNIX 및 UNIX 기반 운영체제에서 프로세스 생성과 프로그램 실행을 효과적으로 관리하는 데 사용된다. fork()
는 프로세스를 생성하고, exec()
는 새로운 프로그램을 실행하는 데 사용된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
int main() {
pid_t pid;
// fork a child process
pid = fork();
// error occurred
if (pid < 0) {
fprinft(stderr, "Fork Failed");
return 1;
}
// child process
else if (pid == 0) {
execlp("/bin/ls", "ls", NULL);
}
// parent process
else {
// parent will wait for the child to complete
wait(NULL);
printf("Child Complete");
}
return 0;
}
위 코드는 부모 프로세스가 자식 프로세스를 생성하고, 자식 프로세스는 새로운 프로그램을 실행한 후 종료될 때까지 대기하는 간단한 프로세스 생성 및 실행 예제이다. 참고 바란다.
💾 Process Termination
프로세스 종료는 프로세스가 실행을 마치고 시스템에 삭제를 요청할 때 발생한다.
- 프로세스의 마지막 명령 실행
- 프로세스는 마지막 명령을 실행 후에 종료를 요청한다.
- 프로세스 종료 요청(exit)
- 프로세스는 실행 후 운영체제에게 종료를 요청함. 이는 보통
exit()
을 반환하는 방식으로 이루어진다.
- 프로세스는 실행 후 운영체제에게 종료를 요청함. 이는 보통
- 부모 프로세스로부터의 결과 전달
- 자식 프로세스가 종료되고 출력 데이터를 부모 프로세스로 전달해야 할 때는
wait()
함수를 사용하여 자식 프로세스의 종료를 기다릴 수 있다.
- 자식 프로세스가 종료되고 출력 데이터를 부모 프로세스로 전달해야 할 때는
- 운영체제에 의한 자원 회수
- 프로세스 종료 요청이 이루어지면 운영체제는 해당 프로세스의 자원을 회수하고 할당된 메모리 및 다른 시스템 자원을 해제한다.
또한, 부모 프로세스는 종종 자식 프로세스의 실행을 종료시킬 수 있다. 이는 자식이 할당된 자원을 초과하거나, 자식이 더 이상 필요하지 않은 작업을 수행할 때 발생할 수 있다.
또한, 부모가 종료될 때는 일부 운영체제에서는 자식이 부모를 따르지 않는다면 모든 자식이 종료될 수 있다. 이를 “계층적 종료(cascaded termination)”이라고 한다.
프로세스 종료는 프로세스 관리와 시스템 자원 관리의 중요한 부분이다. 올바른 종료 절차를 통해 시스템의 안정성과 효율성을 유지하는 데 중요한 역할을 한다.
4️⃣ Inter-Process Communications(IPC)
IPC는 프로세스 간에 데이터를 전송하고 상호작용하기 위한 메커니즘을 제공한다.
프로세스들이 협력하여 작업을 수행하거나 서로 통신해야 할 때 IPC가 필요하다. IPC는 주로 2가지 모델을 사용한다.
- 공유 메모리(Shared Memory)
- 이 모델에서는 프로세스들이 메모리 공간을 공유한다. 한 프로세스가 생성한 데이터나 자원을 다른 프로세스가 접근할 수 있다. 공유 메모리를 사용하면 프로세스 간 데이터 공유가 간단하고 효율적이다.
- 하지만 공유 메모리를 사용할 때 데이터 무결성과 동기화 문제를 처리해야 한다. 한 프로세스가 공유 데이터를 수정하는 동안 다른 프로세스가 동일한 데이터를 읽을 경우 예상치 못한 동작이 발생할 수 있다.
- 메시지 패싱(Message Passing)
- 이 모델에서는 프로세스 간에 메시지를 전송하여 통신한다. 메시지는 명시적으로 송신자에서 수신자로 전달된다. 일반적으로 운영체제나 미들웨어가 이를 관리한다.
- 공유 메모리보다 더 안전하고 격리된 방식으로 통신할 수 있다. 각각의 메시지가 명시적으로 전달되므로 데이터 무결성과 동기화에 대한 걱정이 없다.
- 하지만 메시지 패싱은 공유메모리보다 오버헤드가 높다. 메시지를 전송하고 수신하는 데 시간이 걸리며 데이터를 전달할 때는 시스템콜이 많이 발생하기 때문이다.
IPC는 프로세스간의 상호 작용을 용이하게 만들어주며, 프로세스 간의 정보 공유, 계산 속도 향상, 모듈화, 편의성 등과 같은 협력하는 프로세스의 필요성을 충족시킨다.
💽 Producer-Consumer Problem
협력하는 프로세스 간의 협력적인 작업을 보여주는 프로그래밍 문제의 일종이다.
한 프로세스가 데이터를 생성하고 다른 프로세스가 해당 데이터를 소비하는 상황을 말한다. 이러한 문제를 해결하기 위해서는 보통 공유 자원을 관리하는 방법을 사용한다.
이러한 방법에는 세마포어, 뮤텍스 등의 동기화 기법이 포함될 수 있다. 이를 통해 생산자와 소비자 간의 작업을 조율하여 데이터 손실이나 오류를 방지할 수 있다.
💽 Shared Memory solution
공유 메모리를 이용한 해결책은 생산자-소비자 문제를 해결하는 데 사용되는 하나의 방법이다. 이 방법은 생산자와 소비자 프로세스가 공유하는 메모리 영역을 통해 데이터를 교환한다.
- 공유 메모리 설정
- 먼저, 공유 메모리 영역이 설정되어야 한다. 이 영역은 생산자가 생성한 데이터를 저장하는 버퍼로 사용된다.
- 생산자 작업
- 생산자는 공유 메모리 영역에 데이터를 생성하고 버퍼에 넣는다. 이 때, 생산자는 버퍼가 가득 차 있는지 확인하고 가득 차 있다면 생산자는 대기한다.
- 소비자 작업
- 소비자는 공유 메모리 영역에서 데이터를 읽어온다. 이 때, 소비자는 버퍼가 비어 있는지 확인하고 비어 있다면 소비자는 잠시 대기한다.
- 동기화
- 생산자와 소비자는 공유 메모리 영역에 동시에 접근 가능하기 때문에, 동기화해야 한다. 이를 통해 보통 세마포어나 뮤텍스와 같은 동기화 메커니즘을 사용한다. 이 메커니즘을 사용하여 생산자가 버퍼에 데이터를 쓸 때와 소비자가 데이터를 읽을 때 충돌을 방지한다.
이러한 공유 메모리 해결책은 효율적이고 빠른 데이터 교환을 가능하게 하며, 생산자와 소비자 간의 통신을 용이하게 한다. 하지만 이해 관계에 따라 메모리 동기화 문제 및 공유 자원 관리에 대한 추가적인 주의가 필요할 수 있다.
💽 Message Passing
다른 프로세스에게 데이터를 전달하고 수신하는 과정이다. 이를 통해 프로세스들은 서로 간의 정보를 교환하고 작업을 협력적으로 수행할 수 있다.
두 프로세스 P와 Q가 통신하기 위해서는 아래와 같은 단계를 거치게 된다.
- 통신 링크 설정
- 두 프로세스 간에 통신을 위한 링크를 설정해야 한다. 이는 물리적인 링크일 수도 있고, 운영체제가 제공하는 통신 채널일 수도 있다. 통신 링크는 메시지를 교환하는 데 사용된다.
- 메시지 교환
- send(msg)
- 한 프로세스에서 다른 프로세스로 메시지를 보낸다. 메시지의 크기는 고정되어 있을 수도 있고, 가변적일 수도 있다. send 작업을 통해 메시지를 보내는 프로세스는 메시지를 목적지 프로세스로 전송한다.
- receive(msg)
- 메시지를 수신하는 프로세스는 send 작업을 통해 전송된 메시지를 수신한다. 이 작업은 메시지 크기에 관계 없이 메시지를 받는다. receive 작업을 통해 수신된 메시지는 목적지 프로세스에서 처리된다.
- send(msg)
메시지 전달을 통해 프로세스 간에 데이터를 안전하고 효율적으로 전송할 수 있다.
🌊 Direct Communication
직접 통신은 메시지 패싱에서 사용되는 방법 중 하나이다.
- 명시적인 프로세스 명시
- 각 프로세스는 통신을 위해 프로세스를 명시적으로 지정해야 한다. 예를 들어,
send(P, message)
는 메시지를 프로세스 P에게 보내는 것을 의미하고,receive(Q, message)
는 프로세스 Q로부터 메시지를 받는 것을 의미한다.
- 각 프로세스는 통신을 위해 프로세스를 명시적으로 지정해야 한다. 예를 들어,
- 통신 링크의 속성
- 링크 자동 설정 : 통신을 위해 링크는 자동으로 설정된다.
- 단일한 링크와 프로세스 쌍 : 각 프로세스 쌍 사이에는 단 하나의 링크만 존재한다. 따라서 링크는 정확히 한 쌍의 프로세스에 연결된다.
- 링크의 단방향/양방향 속성이 존재한다.
직접 통신은 메시지를 보내거나 받기 위해 상대 프로세스를 명시적으로 지정해야 하므로, 통신의 명확성과 제어를 제공한다. 이를 통해 프로세스 간의 효율적이고 안전한 통신이 가능하다.
🌊 Indirect Communication
간접 통신은 메시지 패싱에 사용되는 또 다른 방법이다.
- 메일박스 사용
각 프로세스는 메일박스를 통해 메시지를 전달하고 받는다. 메일박스는 고유한 id를 가지며, 프로세스 간 통신을 위해 사용된다. - 통신 링크의 속성
- 메일 박스를 공유하는 프로세스 간의 연결
- 통신을 위한 링크는 오직 프로세스가 공유하는 메일박스가 있는 경우에만 설정된다. 즉, 두 개 이상의 프로세스가 동일한 메일박스에 액세스해야만 통신이 가능하다.
- 하나의 링크와 여러 프로세스
- 링크는 여러 프로세스에 연결될 수 있다. 따라서 링크가 여러 프로세스 간의 통신을 지원할 수 있다.
- 프로세스 쌍 간의 여러 통신 링크
- 각 프로세스 쌍 사이에는 여러 통신 링크가 있을 수 있다. 이는 여러 프로세스가 동일한 메일박스를 통해 통신할 수 있기 때문에 가능하다.
- 링크의 단방향/양방향 속성이 존재한다.
- 메일 박스를 공유하는 프로세스 간의 연결
- 통신 작업
- 새로운 메일박스 생성
- 새로운 메일박스를 생성하여 프로세스 간 통신을 위한 통로를 설정한다.
- 메일박스를 통한 메시지 송수신
- send(M, message)와 receive(M, message)를 사용하여 메일박스를 통해 메시지를 송수신한다.
- 메일박스 파괴
- 더 이상 필요하지 않은 메일박스를 파괴하여 자원을 해제한다.
- 새로운 메일박스 생성
간접 통신은 두 프로세스 간의 통신을 위해 중간 매개체로 메일박스를 사용하여 상호작용한다. 이를 통해 여러 프로세스 간의 효율적인 통신이 가능할 것이다.
💭 퀴즈타임
메일박스를 공유하는 여러 프로세스가 있는 경우, 한 프로세스가 메시지를 보내면 해당 메시지를 받을 프로세스를 결정해야 한다. 예를 들어, P1이 메일박스 M을 통해 메시지를 보내고, 이 메시지를 받을 프로세스는 P2와 P3이다. 그럼 누가 이 메시지를 받을까?
해결책은 아래와 같다.
- 두 개의 프로세스와 관련된 링크 허용
각 링크는 두 개의 프로세스 간에만 연결된다. 이렇게 하면 메일박스를 공유하는 여러 프로세스 중에서 두 개의 프로세스만이 메시지를 교환할 수 있다. - 수신 작업을 동시에 하나의 프로세스에만 허용
메일박스에서 메시지를 수신하는 동작은 한 번에 한 프로세스만 실행할 수 있다. 따라서 P2와 P3 중 하나만이 메시지를 받을 수 있다. - 시스템이 수신자를 임의로 선택
시스템은 메시지를 받을 프로세스를 임의로 선택 가능하다. 이 경우 발신자는 수신자가 누구인지 알 수 있다.
이러한 해결책 중 하나를 택하여 메일박스를 공유하는 여러 프로세스 간의 효율적인 메시지 교환이 가능하다.
🌊 Synchronization
동기화는 병렬 프로그래밍 및 다중 프로세스 환경에서 프로세스 간의 상호작용을 조절하는 개념이다. 메시지 패싱에서의 동기화는 두 가지 방식으로 나뉜다.
- 블록킹 동기화
- 블록킹 동기화는 동기화 작업이 완료될 때까지 프로세스가 대기하는 방식이다. 이는 동기화 작업이 완료될 때까지 프로세스가 다음 작업으로 진행되지 않음을 의미한다.
- 블록킹 send는 메시지를 전송 후 메시지가 수신될 때까지 보내는 프로세스가 대기한다.
- 블록킹 receive는 메시지를 수신한 후 메시지가 도착할 때까지 수신하는 프로세스가 대기한다.
- 논블록킹 동기화
- 논블록킹 동기화는 동기화 작업이 진행되는 동안 다른 작업을 수행할 수 있도록 허용하는 방식이다. 이는 동기화 작업이 완료될 때까지 프로세스가 대기하지 않고 다른 작업을 처리 가능하다.
- 논블록킹 send는 메시지를 보낸 후 즉시 다음 작업을 진행한다. 메시지가 받는 프로세스에 도달할 때까지 대기하지 않는다.
- 논블록킹 receive는 메시지를 받는 경우 해당 메시지를 즉시 처리하고, 메시지가 아직 도착하지 않은 경우 null 값을 반환하거나 다른 작업을 수행한다.
동기화는 프로세스 간의 상호작용을 조절하고 일관된 실행을 보장하는 데 중요하다. 블록킹 동기화는 상호작용의 완전성을 보장하며, 논블록킹 동기화는 프로세스의 효율성을 높이고 비동기적인 통신을 가능하게 한다.
🌊 Buffering
버퍼링은 통신 링크에 연결된 메시지의 대기열을 관리하는 방법이다. 메시지가 보내지는 속도와 받아지는 속도가 다를 때 발생하는 상황을 처리하기 위한 메커니즘이다. 3가지의 버퍼링이 존재한다.
- Zero capacity
- 용량이 0인 버퍼링으로 메시지가 직접적으로 수신자에게 전달되어야 하며, 버퍼가 없다. 따라서 송신자는 수신자와의
랑데뷰(Rendezvous)
를 기다려야 한다. 이는 송신자가 메시지를 보낼 때 수신자가 반드시 준비되어 있어야 함을 의미한다.
- 용량이 0인 버퍼링으로 메시지가 직접적으로 수신자에게 전달되어야 하며, 버퍼가 없다. 따라서 송신자는 수신자와의
- Bounded capacity
- 유한 용량의 버퍼링으로 메시지의 일시적인 대기열을 관리한다. 버퍼에는 유한한 개수의 메시지가 저장될 수 있으며, 만약 버퍼가 가득 찬 경우 송신자는 대기해야 한다. 따라서 버퍼가 가득 차면 송신자는 메시지를 보내지 못하고 대기해야 한다.
- Unbounded capacity
- 무한 용량의 버퍼링으로 메시지 대기열의 크기에 제한이 없다. 따라서 버퍼가 가득 차지 않기 때문에 송신자는 대기하지 않고 메시지를 보낼 수 있다. 이는 송신자가 메시지를 보낼 때 항상 수신자가 버퍼를 비울 필요가 없음을 의미한다.
버퍼링은 통신 시스템에서 중요한 역할을 한다. 적절한 버퍼링은 메시지 전달의 신뢰성과 성능을 향상시킬 수 있다.
💽 Sockets
IPC에서 소켓은 엔드포인트를 나타낸다. 소켓은 네트워크에서 사용되는 개념으로, 주소와 포트 번호로 식별된다. IPC에서 소켓은 일반적으로 네트워크 소켓과 유사한 방식으로 동작하며, 로컬 또는 원격 프로세스 간에 통신을 가능하게 한다.
- 엔드포인트
- 소켓은 통신의 엔드포인트로서, 데이터를 전송하거나 수신할 수 있는 지점을 제공해준다.
- IP 주소와 포트 번호의 결합
- 소켓은 IP 주소와 포트 번호의 결합으로 식별된다. 예를 들어, “161.26.19.8:1625”라는 소켓은 호스트 “161.26.19.8”의 포트번호 1625를 가리킨다.
- 소켓 쌍 간의 통신
- IPC에서 통신은 두 소켓 간에 이루어진다. 두 소켓 간의 통신은 데이터의 송수신을 포함하며, 이를 통해 두 프로세스 간의 상호작용이 가능해진다.
💽 Remote Procedure Call(RPC)
RPC(원격 프로시저 호출)는 네트워크 상의 프로세스 간에 프로시저 호출을 추상화하는 기술이다. 이는 원격 시스템에서 다른 시스템에 있는 프로시저를 호출할 수 있도록 한다. RPC는 보통 클라이언트와 서버 간의 통신을 단순화하고, 분산 시스템에서 프로그래밍을 용이하게 한다.
- Stub(스텁)
- 클라이언트와 서버 간의 통신을 중개하는 인터페이스다. 클라이언트 측 스텁과 서버 측 스텁으로 구분된다.
- 클라이언트 측 스텁은 실제 프로시저가 실행되는 서버를 찾고, 매개변수를 마샬링하여 네트워크를 통해 전송한다.
- 서버 측 스텁은 메시지를 받고, 마샬링된 매개변수를 언마샬링하여 서버에서 프로시저를 수행한다.
- 마샬링/언마샬링
- RPC에서는 클라이언트와 서버 간에 데이터를 전송하기 위해 데이터를 직렬화하고 역직렬화하는 과정이 필요하다. 이를 마샬링/언마샬링이라고 한다.
- MIDL(Microsoft Interface Definition Language)
- Windows에서 RPC를 구현할 때 사용되는 스텁 코드는 MIDL을 통해 명세로부터 생성된다. MIDL은 클라이언트와 서버 간의 프로시저 호출을 정의하고, 스텁 코드를 생성하기 위한 Microsoft의 인터페이스 정의 언어이다.
RPC는 분산 시스템에서 효율적인 서비스 제공을 가능하게 하고, 시스템 간의 상호작용을 단순화하여 프로그램의 복잡성을 줄이는 데 도움이 된다.
💽 Pipes
파이프는 두 프로세스 간에 데이터를 전달하는 데 사용되는 통로로, 한 프로세스의 출력을 다른 프로세스의 입력으로 연결한다. 파이프는 프로세스 간 통신을 위한 간단하고 효율적인 메커니즘으로서, 주로 리눅스/유닉스 기반 시스템에서 사용된다.
파이프를 구현할 때는 고려해야 할 여러 이슈가 존재한다.
- 단방향 vs. 양방향
- 파이프는 단방향(단일 방향으로만 데이터 흐름이 가능한) 또는 양방향(두 방향으로 데이터 흐름이 가능한)일 수 있다.
- 반이중 vs. 전이중
- 반이중 파이프는 한 번에 한 방향으로만 데이터를 전송할 수 있지만, 전이중 파이프는 두 방향으로 동시에 데이터를 전송할 수 있다.
- Among networked system vs. On the same machine
- 파이프는 네트워크 시스템에서 사용할 수도 있고, 동일한 컴퓨터의 프로세스 간에만 사용할 수도 있다.
파이프에는 두 가지 주요 유형이 존재한다.
- Ordinary pipes
- 두 프로세스 간의 통신을 위한 표준 생산자-소비자 방식을 지원한다. 즉, 한 프로세스가 파이프의 한쪽 끝에 데이터를 쓰고, 다른 프로세스가 다른 쪽 끝에서 데이터를 읽는다.
- 단방향이며, 통신이 완료되고 프로세스가 종료되면 파이프가 소멸된다.
- 파이프는 생성한 프로세스 외부에서 접근할 수 없다. 일반적으로 부모 프로세스가 파이프를 생성하고
fork()
를 통해 생성된 자식 프로세스와 통신하는 데 사용된다.
- Named pipes
- 양방향이며, 부모-자식 관계가 필요하지 않음.
- 한 번 설정하면 여러 프로세스가 통신에 사용할 수 있다.
- 통신이 완료된 후에도
Named pipes
는 계속 존재한다.
💭 퀴즈타임
What is the difference between pipe and message passing?
파이프와 메시지 패싱은 프로세스 간 통신에서 사용되는 주요 데이터 전송 방식이다. 차이점은 아래에서 설명하겠다.
- 비트 스트림(Pipes)
- 비트 스트림은 단순히 비트의 연속적인 스트림으로, 데이터의 구조나 형식에 대한 정보가 없는 경우가 많다.
- 파이프는 데이터를 비트 단위로 전송하며, 데이터의 구조나 형식을 명확하게 정의하지 않는다.
- 일반적으로 파이프는 단순한 텍스트 또는 이진 데이터를 전송하는 데 사용된다.
- 구조화된 메시지(Message passing)
- 구조화된 메시지는 메시지 내에 데이터의 구조를 명확하게 정의하고, 필요한 경우 메타데이터를 포함할 수 있다.
- 메시지 전달은 보통 구조체, 객체 또는 프로토콜 버퍼와 같은 형식을 사용하여 데이터를 구조화하고 전송한다.
- 메시지 패싱은 데이터의 의미와 구조를 보다 명확하게 전달할 수 있으며, 다양한 유형의 데이터를 전송하는 데 유용하다.
즉, 파이프는 비트 스트림을 통해 데이터를 전송하고, 메시지 패싱은 구조화된 메시지를 통해 데이터를 전송한다.
비트 스트림은 데이터의 구조를 명시적으로 정의하지 않고 전송하는 반면, 구조화된 메시지는 데이터의 구조를 명확하게 정의하여 전달한다.
5️⃣ 마무리
정말 긴 글이었다. 오늘은 프로세스에 관한 글이었다. 프로세스 상태, 스케줄링, 프로세스 연산을 통해 프로세스에 대해서 전반적으로 알아보았다.
또한, 프로세스 간에 데이터를 교환하고 상호작용하기 위한 메커니즘인 IPC에 대해 알아보았다. IPC에는 여러 방법이 존재하는데 마무리로 간단하게 설명을 하고 글을 마치겠다.
종류 | 설명 |
---|---|
Producer-Consumer Problem | 한 프로세스가 데이터를 생산하고 다른 프로세스가 이를 소비하는 상황에서 발생하는 동기화 문제이다. |
Shared Memory | 프로세스 간에 공유된 메모리 영역을 사용하여 데이터를 공유하는 방법이다. |
Message Passing | 메시지를 보내고 받아서 통신하는 방법으로, 프로세스는 명시적으로 메시지를 주고 받는다. |
Sockets | 네트워크 상에서 프로세스 간 통신을 위한 인터페이스로, TCP/IP와 같은 프로토콜을 기반으로 한다. |
Remote Procedure Call(RPC) | 원격 시스템에 있는 프로시저를 호출하는 메커니즘으로, 로컬 프로시저 호출과 유사한 방식으로 작동한다. |
Pipes | 두 프로세스 간의 통신을 위한 간단한 방법으로, 비트 스트림을 통해 통신한다. |
자세한 내용은 위 글을 차근차근 읽어보길 바라며 마무리하겠다. 이만 안녕~👻
-
댓글남기기