프로세스

2026. 5. 26. 13:14·개인공부/OS

프로세스 개념

운영체제에서 모든 CPU 활동을 어떻게 부를 것인가에 대한 문제가 존재.

초기의 일괄처리 시스템에서는 작업이라는 용어가 사용됨.

시분할 시스템에서는 사용자 프로그램 또는 태스크라는 용어가 사용됨.

현대 운영체제에서는 실행 중인 프로그램을 프로세스라고 부름.

프로세스는 현대 컴퓨팅 시스템에서 작업의 단위.

 

프로세스

프로세스는 실행 중인 프로그램.

프로세스의 현재 활동 상태는 프로그램 카운터 값과 프로세서 레지스터의 내용으로 표현됨.

프로세스의 메모리 배치는 여러 섹션으로 구성.

텍스트 섹션은 실행 코드가 들어 있는 영역.

데이터 섹션은 전역 변수가 저장되는 영역.

힙은 프로그램 실행 중 동적으로 할당되는 메모리 영역.

스택은 함수 호출 시 임시 데이터가 저장되는 영역.

스택에는 함수 매개변수, 복귀 주소, 지역 변수 등이 저장됨.

텍스트 섹션과 데이터 섹션의 크기는 고정됨.

힙과 스택은 프로그램 실행 중 동적으로 변화 가능.

함수가 호출될 때 스택에는 함수 매개변수, 지역 변수, 복귀 주소를 포함하는 활성화 레코드가 저장됨.

함수에서 되돌아오면 활성화 레코드는 스택에서 제거됨.

힙은 메모리가 동적으로 할당될 때 커지고, 메모리가 반환되면 줄어드는 구조.

프로그램 그 자체는 프로세스가 아님.

프로그램은 명령어 리스트를 내용으로 가진 디스크 파일처럼 수동적인 개체.

프로세스는 다음에 실행할 명령어를 지정하는 프로그램 카운터와 관련 자원 집합을 가진 능동적인 개체.

실행 파일이 메모리에 적재되면 프로그램은 프로세스가 됨.

실행 파일을 메모리에 적재하는 일반적인 방법은 

파일 아이콘을 클릭하거나 명령어 라인에서 프로그램 이름을 입력하는 방식.

같은 프로그램도 여러 개의 프로세스가 될 수 있음.

두 사용자가 같은 프로그램을 실행하거나, 

한 사용자가 같은 프로그램을 여러 번 실행하면 각각 별도의 프로세스가 생성됨.

이 경우 텍스트 섹션은 같을 수 있지만 데이터 섹션, 힙, 스택은 서로 다른 구조.


 

프로세스 상태

프로세스는 실행되면서 상태가 변함.

프로세스 상태는 그 프로세스의 현재 활동을 나타냄.

프로세스 상태는 새로운 상태, 실행 상태, 대기 상태, 준비 상태, 종료 상태로 구분.

새로운 상태는 프로세스가 생성 중인 상태.

실행 상태는 명령어들이 실행되고 있는 상태.

대기 상태는 프로세스가 어떤 이벤트가 발생하기를 기다리는 상태.

준비 상태는 프로세스가 처리기에 할당되기를 기다리는 상태.

종료 상태는 프로세스의 실행이 종료된 상태.

한 순간에 하나의 처리기 코어에서는 오직 하나의 프로세스만 실행 상태일 수 있음.

준비 상태와 대기 상태에는 여러 프로세스가 존재 가능.

입출력 또는 이벤트 대기가 발생하면 프로세스는 실행 상태에서 대기 상태로 이동.

입출력 또는 이벤트 완료가 발생하면 프로세스는 대기 상태에서 준비 상태로 이동.

인터럽트가 발생하면 프로세스는 실행 상태에서 준비 상태로 이동 가능.

프로세스가 종료되면 실행 상태에서 종료 상태로 이동.

 

프로세스 제어 블록

각 프로세스는 운영체제에서 프로세스 제어 블록으로 표현됨.

프로세스 제어 블록은 PCB.

PCB는 특정 프로세스와 관련된 여러 정보를 포함.

PCB에 포함되는 정보는 

프로세스 상태, 프로그램 카운터, CPU 레지스터, CPU 스케줄링 정보, 메모리 관리 정보, 회계 정보, 입출력 상태 정보.

프로세스 상태는 새로운 상태, 준비 상태, 실행 상태, 대기 상태, 정지 상태와 같은 현재 상태 정보.

프로그램 카운터는 이 프로세스가 다음에 실행할 명령어의 주소.

CPU 레지스터는 컴퓨터 구조에 따라 다양한 수와 유형을 가짐.

CPU 레지스터에는 누산기, 인덱스 레지스터, 스택 포인터, 범용 레지스터, 상태 코드 정보 등이 포함될 수 있음.

인터럽트가 발생하면 프로세스가 나중에 계속 올바르게 실행되도록 레지스터 값이 저장되어야 함.

CPU 스케줄링 정보는 프로세스 우선순위, 스케줄링 큐에 대한 포인터, 다른 스케줄링 매개변수 등을 포함.

메모리 관리 정보는 운영체제가 사용하는 메모리 시스템에 따라 필요한 정보.

메모리 관리 정보에는 베이스 레지스터와 한계 레지스터 값, 페이지 테이블, 세그먼트 테이블 같은 정보가 포함될 수 있음.

회계 정보는 CPU 사용 시간, 경과된 실제 시간, 시간 제한, 계정 번호, 잡 또는 프로세스 번호 등을 포함.

입출력 상태 정보는 프로세스에 할당된 입출력 장치 목록과 열린 파일 목록 등을 포함.

PCB는 프로세스를 시작하거나 다시 시작하는 데 필요한 모든 데이터를 저장하는 저장소.

 

스레드

현대 운영체제는 프로세스가 한 번에 하나 이상의 일을 수행할 수 있도록 프로세스 개념을 확장.

하나의 프로세스가 여러 스레드를 가지면 여러 실행 흐름이 같은 프로세스 안에서 병행 가능.

다중 스레드 프로세스에서는 각 스레드에 대한 정보를 포함하도록 PCB가 확장됨.

스레드 지원을 위해 운영체제 전체 구조에도 변화 필요.


 

프로세스 스케줄링

다중 프로그래밍의 목적은 CPU 이용률을 최대화하기 위해 항상 어떤 프로세스가 실행되도록 하는 것.

시분할의 목적은 프로그램이 실행되는 동안 사용자가 상호작용할 수 있도록 

프로세스 사이에서 CPU 코어를 빈번하게 교체하는 것.

프로세스 스케줄러는 코어에서 실행 가능한 여러 프로세스 중 하나를 선택.

단일 CPU 코어에서는 한 번에 오직 하나의 프로세스만 실행 가능.

한 코어 시스템에 실행 가능한 프로세스가 여러 개 있으면 나머지 프로세스는 CPU 코어가 사용 가능해질 때까지 대기.

프로세스는 I/O 바운드 프로세스 또는 CPU 바운드 프로세스로 구분.

I/O 바운드 프로세스는 계산보다 입출력에 많은 시간을 소비하는 프로세스.

CPU 바운드 프로세스는 입출력보다 계산에 많은 시간을 소비하는 프로세스.

 

스케줄링 큐

프로세스가 시스템에 들어가면 준비 큐에 들어가 준비 상태가 되어 CPU 코어에서 실행되기를 기다림.

준비 큐는 일반적으로 연결 리스트로 저장.

준비 큐 헤더에는 리스트의 첫 번째 PCB에 대한 포인터와 마지막 PCB에 대한 포인터가 포함.

각 PCB에는 준비 큐의 다음 PCB를 가리키는 포인터 필드가 포함 가능.

시스템에는 준비 큐뿐 아니라 여러 대기 큐가 존재.

프로세스에 CPU 코어가 할당되어 실행 중일 때 입출력 요청을 하면 프로세스는 입출력 사용 가능 때까지 기다려야 함.

입출력 완료 같은 특정 이벤트 발생을 기다리는 프로세스는 대기 큐에 삽입됨.

프로세스 스케줄링은 큐잉 다이어그램으로 표현 가능.

새 프로세스는 처음 준비 큐에 들어감.

프로세스는 실행을 위해 선택되거나 디스패치될 때까지 기다림.

CPU 코어가 할당되고 실행 상태가 되면 

입출력 요청, 자식 프로세스 대기, 인터럽트 또는 타임 슬라이스 만료 같은 이벤트가 발생 가능.

입출력 또는 이벤트 완료 후 프로세스는 다시 준비 큐에 들어감.

프로세스는 종료될 때까지 이 주기를 계속.

종료 시점에는 모든 큐에서 제거되고 PCB와 자원이 반환됨.

Linux 운영체제의 프로세스 제어 블록은 C 구조체 task_struct로 표현.

task_struct는 프로세스 상태, 스케줄링과 메모리 관리 정보, 

열린 파일과 부모 및 자식 프로세스의 리스트를 가리키는 포인터 등을 포함.

 

CPU 스케줄링

프로세스는 수행 주기 동안 준비 큐와 다양한 대기 큐를 오감.

CPU 스케줄러의 역할은 준비 큐에 있는 프로세스 중 하나를 선택하여 CPU 코어를 할당하는 것.

CPU 스케줄러는 CPU를 할당하기 위해 새 프로세스를 자주 선택해야 함.

I/O 바운드 프로세스는 입출력 요청 전까지 몇 밀리초 동안만 실행되는 경우가 많음.

CPU 바운드 프로세스는 오랜 시간 동안 CPU 코어가 필요.

스케줄러는 하나의 프로세스가 장시간 CPU 코어를 독점하지 않도록 설계됨.

일부 운영체제는 스와핑으로 알려진 중간 형태의 스케줄링을 사용.

스와핑의 핵심은 메모리에서 프로세스를 제거하여 다중 프로그래밍 정도를 낮추는 것.

나중에 프로세스를 다시 메모리에 적재하고 중단된 위치에서 실행을 계속 가능.

프로세스를 메모리에서 디스크로 스와핑 아웃하고, 다시 메모리로 스와핑 인하는 방식.

스와핑은 일반적으로 메모리가 초과 사용되어 가용 공간 확보가 필요할 때 사용.

 

문맥 교환

인터럽트는 운영체제가 CPU 코어를 현재 작업에서 빼내어 커널 루틴을 실행할 수 있게 함.

인터럽트가 발생하면 현재 실행 중인 프로세스의 문맥을 저장해야 하며, 작업이 끝난 뒤 그 문맥을 복구해야 함.

문맥은 프로세스의 PCB에 표현됨.

문맥은 CPU 레지스터 값, 프로세스 상태, 메모리 관리 정보 등을 포함.

CPU 코어를 다른 프로세스로 교환하려면 현재 프로세스의 상태를 보관하고 새 프로세스의 보관된 상태를 복구해야 함.

이 작업이 문맥 교환.

문맥 교환이 일어나면 커널은 이전 프로세스의 문맥을 PCB에 저장하고, 

실행이 스케줄된 새 프로세스의 저장된 문맥을 복구.

문맥 교환 시간은 순수한 오버헤드.

교환 중에는 시스템이 유용한 작업을 수행하지 않기 때문.

교환 속도는 메모리 속도, 복사되어야 하는 레지스터 수, 특수 명령어의 존재 여부에 따라 달라짐.

문맥 교환 시간은 하드웨어 지원에 크게 좌우됨.

운영체제가 복잡할수록 문맥 교환 시 해야 할 작업도 많아질 수 있음.

고급 메모리 관리 기법을 사용하는 경우, 문맥 교환 시 더 많은 자료를 교환해야 할 수 있음.

주소 공간은 반드시 보존되어야 하며 다음 프로세스의 사용을 위해 준비되어야 함.



프로세스에 대한 연산

대부분 시스템 내의 프로세스들은 병행 실행될 수 있으며 동적으로 생성되고 제거되어야 함.

운영체제는 프로세스 생성 및 종료를 위한 기법을 제공해야 함.

 

프로세스 생성

실행되는 동안 프로세스는 여러 개의 새로운 프로세스를 생성 가능.

생성하는 프로세스는 부모 프로세스.

생성되는 프로세스는 자식 프로세스.

새로운 프로세스들도 다시 다른 프로세스들을 생성할 수 있음.

그 결과 프로세스 트리 형성.

대부분의 현대 운영체제는 유일한 프로세스 식별자 pid를 사용하여 프로세스 구분.

pid는 시스템의 각 프로세스에 고유한 값을 제공하며, 

커널이 유지하고 있는 프로세스의 다양한 속성에 접근하기 위한 색인 역할.

Linux에서는 pstree 명령으로 모든 프로세스 트리를 확인 가능.

systemd 프로세스는 모든 사용자 프로세스의 루트 부모 프로세스 역할.

시스템이 부팅되면 systemd 프로세스가 생성됨.

systemd 프로세스는 사용자 프로세스를 생성함.

자식 프로세스는 운영체제로부터 직접 자원을 얻을 수도 있고, 부모 프로세스 자원의 부분 집합을 사용할 수도 있음.

부모가 자원 일부만 자식에게 사용하게 하면 자식 프로세스가 시스템을 과부하시키는 일을 방지 가능.

부모 프로세스가 자식 프로세스를 생성할 때 부모와 자식이 병행 실행을 계속할 수도 있음.

부모가 일부 또는 모든 자식의 실행 종료를 기다릴 수도 있음.

새로운 프로세스의 주소 공간은 부모 프로세스의 복사본일 수도 있음.

새로운 프로세스의 주소 공간에 새로운 프로그램이 적재될 수도 있음.

UNIX 운영체제에서는 fork 시스템 콜로 새 프로세스 생성.

새로운 프로세스는 원래 프로세스의 주소 공간 복사본으로 구성.

fork 이후 두 프로세스는 fork 호출 이후의 명령어부터 실행을 계속.

부모에게는 자식의 pid가 반환되고, 자식에게는 0이 반환됨.

fork 이후 한 프로세스가 exec 시스템 콜을 사용하면 자신의 메모리 공간을 새로운 프로그램으로 대체.

부모는 wait 시스템 콜을 통해 자식 프로세스가 종료될 때까지 준비 큐에서 자신을 제거할 수 있음.

Windows에서는 CreateProcess API를 사용하여 프로세스 생성.

CreateProcess는 fork와 달리 새 프로세스를 만들면서 지정된 프로그램을 주소 공간에 적재.

Windows 예에서는 STARTUPINFO와 PROCESS_INFORMATION 구조체 사용.

STARTUPINFO는 새 프로세스의 윈도우와 표준 입출력 특성 지정.

PROCESS_INFORMATION은 새로 생성된 프로세스와 스레드의 핸들과 식별자 정보 포함.

부모 프로세스는 WaitForSingleObject를 사용해 자식 프로세스가 끝나기를 기다릴 수 있음.

자식 프로세스가 종료되면 CloseHandle로 프로세스와 스레드 핸들을 닫는 구조.

 

프로세스 종료

프로세스가 마지막 문장의 실행을 끝내고 exit 시스템 콜을 사용하여 운영체제에 삭제를 요청하면 종료.

프로세스는 자신을 기다리는 부모 프로세스에 상태 값을 반환 가능.

물리 메모리와 가상 메모리, 열린 파일, 입출력 버퍼를 포함한 프로세스의 모든 자원은 운영체제에 의해 해제.

프로세스 종료는 정상 종료뿐 아니라 다른 프로세스에 의해 발생 가능.

한 프로세스는 적당한 시스템 콜을 통해 다른 프로세스의 종료를 유발 가능.

일반적으로 이러한 호출은 종료될 프로세스의 부모만 수행 가능.

부모가 자식 프로세스를 종료할 수 있는 이유는 자원 초과 사용, 태스크 불필요, 부모 종료 후 자식 실행 불허 등이 있음.

부모 프로세스가 종료된 이후 자식 프로세스가 존재할 수 없는 시스템에서는 연쇄식 종료가 발생.

UNIX와 Linux 시스템에서 exit 시스템 콜은 종료 상태를 나타내는 인자를 전달.

부모 프로세스는 wait 시스템 콜을 사용하여 자식 프로세스가 종료될 때를 기다리고 종료 상태를 얻음.

wait는 종료된 자식의 프로세스 식별자를 반환.

프로세스가 종료되면 사용하던 자원은 운영체제가 되찾음.

종료 상태와 프로세스 테이블 항목은 부모가 wait를 호출할 때까지 남아 있을 수 있음.

종료되었지만 부모가 아직 wait를 호출하지 않은 프로세스는 좀비 프로세스.

부모가 wait를 호출하지 않고 종료하면 자식 프로세스는 고아 프로세스.

전통적 UNIX에서는 init 프로세스가 고아 프로세스의 새 부모 역할.

대부분의 Linux 시스템에서는 systemd가 고아 프로세스를 케어.


프로세스 간 통신

 

운영체제 내에서 실행되는 병행 프로세스들은 독립적이거나 협력적일 수 있음.

프로세스가 시스템에서 실행 중인 다른 프로세스와 데이터를 공유하지 않으면 독립적 프로세스.

프로세스가 다른 프로세스에 영향을 주거나 받고 자료를 공유하면 협력적 프로세스.

협력적 프로세스를 허용하는 이유는 정보 공유, 계산 가속화, 모듈성.

정보 공유는 여러 응용 프로그램이 동일한 정보를 사용할 필요가 있을 때 협력 환경을 제공해야 한다는 의미.

계산 가속화는 특정 태스크를 빨리 실행하기 위해 여러 서브태스크로 나누고 병렬 실행해야 한다는 의미.

이러한 가속화는 복수 처리 코어를 가진 경우에만 달성 가능.

모듈성은 시스템 기능을 별도의 프로세스 또는 스레드로 나누어 모듈식 형태로 구성하기 위한 목적.

협력적 프로세스는 데이터를 교환할 수 있어야 함.

프로세스 간 통신은 IPC(Inter-Process Communication)라고 부름.

IPC에는 공유 메모리 모델과 메시지 전달 모델이 있음.

공유 메모리 모델은 협력 프로세스들에 의해 공유되는 메모리 영역을 구축.

프로세스들은 이 공유 영역에 읽고 쓰면서 정보를 교환.

메시지 전달 모델은 통신하는 프로세스 사이에 교환되는 메시지를 통해 통신.

메시지 전달은 적은 양의 데이터 교환에 유용.

메시지 전달은 분산 시스템에서 공유 메모리보다 구현이 쉬운 편.

공유 메모리는 메모리 영역을 구축할 때만 시스템 콜이 필요하고 

이후 접근은 일반 메모리 접근처럼 처리되므로 메시지 전달보다 빠른 편.

공유 메모리에서는 여러 프로세스가 같은 메모리에 동시에 접근할 때 동기화 필요.

Chrome 브라우저는 다중 프로세스 구조를 사용.

브라우저 프로세스는 사용자 인터페이스와 디스크 및 네트워크 입출력을 관리.

렌더러 프로세스는 HTML, JavaScript, 이미지 등을 처리하기 위한 로직을 포함.

플러그인 프로세스는 Flash 또는 QuickTime 같은 플러그인을 실행.

다중 프로세스 방식은 웹사이트가 다른 웹사이트와 고립되어 보이게 함.

렌더러 프로세스는 샌드박스 안에서 실행되어 보안 취약점 영향을 줄이는 구조.


 

 

공유 메모리 시스템에서의 프로세스 간 통신

공유 메모리를 사용하는 프로세스 간 통신에서는 통신하는 프로세스들이 공유 메모리 영역을 구축해야 함.

공유 메모리 영역은 공유 메모리 세그먼트를 생성하는 프로세스의 주소 공간에 위치.

다른 프로세스들은 자신의 주소 공간에 그 공유 메모리 세그먼트를 첨부해야 함.

운영체제는 보통 한 프로세스가 다른 프로세스의 메모리에 접근하는 것을 금지.

공유 메모리 기법은 둘 이상의 프로세스가 이러한 제한을 제거하는 데 동의하는 방식.

데이터의 형식과 위치는 운영체제의 책임이 아니라 프로세스들의 책임.

같은 위치에 동시에 쓰지 않도록 책임지는 것도 프로세스들의 역할.

협력하는 프로세스 개념을 설명하기 위해 생산자-소비자 문제 사용.

생산자 프로세스는 정보를 생산하고, 소비자 프로세스는 정보를 소비.

컴파일러는 어셈블리 코드를 생산하고, 어셈블러는 이를 소비.

웹 서버는 HTML 파일이나 이미지 같은 웹 콘텐츠를 생산하고, 웹 브라우저는 이를 소비.

생산자와 소비자가 병행 실행되도록 하려면 생산자가 정보를 채워 넣고 소비자가 소비할 수 있는 항목들의 버퍼가 필요.

버퍼에는 무한 버퍼와 유한 버퍼가 있음.

무한 버퍼는 버퍼 크기에 실질적 한계가 없다고 보는 버퍼.

소비자는 새 항목을 기다릴 수 있지만, 생산자는 항상 새 항목을 생산 가능.

유한 버퍼는 버퍼 크기가 고정된 버퍼.

버퍼가 비어 있으면 소비자는 기다려야 함.

버퍼가 가득 차 있으면 생산자는 기다려야 함.

공유 메모리 예시에서는 논리 포인터 in과 out을 가진 원형 배열을 사용.

in은 버퍼에서 다음으로 비어 있는 위치를 가리킴.

out은 버퍼에서 첫 번째 차 있는 위치를 가리킴.

in == out이면 버퍼가 비어 있는 상태.

((in + 1) % BUFFER_SIZE) == out이면 버퍼가 가득 찬 상태.

생산자 프로세스는 새로 생산한 item을 버퍼에 넣은 뒤 in을 갱신.

소비자 프로세스는 버퍼에서 item을 꺼낸 뒤 out을 갱신.

이 구현은 최대 BUFFER_SIZE - 1개의 항목만 버퍼에 수용 가능.

공유 버퍼에 대한 코드는 생산자와 소비자가 병행하여 접근할 수 있으므로 동기화 문제가 남음.


 

메시지 전달 시스템에서의 프로세스 간 통신

메시지 전달 방식은 동일한 주소 공간을 공유하지 않고 프로세스들이 통신하고 동기화할 수 있도록 하는 기법.

분산 환경에서 통신하는 프로세스들이 네트워크로 연결된 다른 컴퓨터에 존재할 수 있으므로 특히 유용.

메시지 전달 설비는 최소한 두 가지 연산을 제공.

send(message)는 메시지를 보내는 연산.

receive(message)는 메시지를 받는 연산.

프로세스가 보낸 메시지는 고정 길이일 수도 있고 가변 길이일 수도 있음.

고정 길이 메시지는 시스템 수준 구현이 간단하지만 프로그래밍 작업을 더 어렵게 만들 수 있음.

가변 길이 메시지는 프로그래밍은 더 단순하지만 시스템 수준 구현이 복잡할 수 있음.

프로세스 A와 B가 통신을 원하면 그들 사이에 통신 링크가 존재해야 함.

메시지 전달에서 링크와 send/receive 연산의 논리적 구현 방식은 직접 또는 간접 통신, 

동기식 또는 비동기식 통신, 자동 또는 명시적 버퍼링으로 구분 가능.

 

명명

통신을 원하는 프로세스들은 서로를 가리킬 방법이 필요.

명명 방식에는 직접 통신과 간접 통신이 있음.

직접 통신에서 통신을 원하는 각 프로세스는 통신의 수신자 또는 송신자의 이름을 명시해야 함.

send(P, message)는 프로세스 P에 메시지를 전송하는 연산.

receive(Q, message)는 프로세스 Q로부터 메시지를 수신하는 연산.

직접 통신에서는 통신을 원하는 각 프로세스의 쌍들 사이에 연결이 자동으로 구축됨.

연결은 정확히 두 프로세스 사이에만 관련됨.

통신하는 프로세스들의 각 쌍 사이에는 정확히 하나의 연결이 존재.

직접 통신 방식은 대칭성을 보임.

비대칭 방식에서는 송신자는 수신자의 이름을 명시하지만 수신자는 송신자 이름을 명시하지 않음.

간접 통신에서 메시지는 메일박스 또는 포트로 송신되고 그곳으로부터 수신됨.

메일박스는 프로세스들이 메시지를 넣고 꺼낼 수 있는 객체.

각 메일박스는 고유 식별자를 가짐.

프로세스는 공유 메일박스를 가진 경우에만 통신 가능.

한 쌍의 프로세스 사이 연결은 이들 프로세스가 공유 메일박스를 가질 때만 구축됨.

연결은 두 개 이상의 프로세스들과 관련될 수 있음.

통신하고 있는 각 프로세스 사이에는 다수의 서로 다른 연결이 존재할 수 있고, 각 연결은 하나의 메일박스에 대응.

여러 프로세스가 하나의 메일박스를 공유하면 누가 메시지를 받을 것인지 결정해야 하는 문제가 발생.

메일박스는 프로세스 또는 운영체제에 의해 소유 가능.

메일박스가 프로세스에 의해 소유되면 해당 메일박스는 프로세스 주소 공간의 일부.

운영체제가 소유한 메일박스는 독립적으로 존재하며 특정 프로세스에 속하지 않음.

운영체제는 새 메일박스 생성, 메일박스를 통한 메시지 송수신, 메일박스 삭제 연산 제공.

 

동기화

프로세스 간 통신은 send와 receive 프리미티브 호출에 의해 발생.

각 프리미티브를 구현하기 위한 설계 옵션은 봉쇄형과 비봉쇄형으로 구분.

메시지 전달은 봉쇄형 또는 비봉쇄형 방식으로 전달 가능.

이 두 방식은 동기식 또는 비동기식 방식이라고도 불림.

봉쇄형 보내기는 송신하는 프로세스가 메시지가 수신 프로세스 또는 메일박스에 의해 수신될 때까지 봉쇄되는 방식.

비봉쇄형 보내기는 송신하는 프로세스가 메시지를 보내고 작업을 계속하는 방식.

봉쇄형 받기는 메시지가 이용 가능할 때까지 수신 프로세스가 봉쇄되는 방식.

비봉쇄형 받기는 수신하는 프로세스가 유효한 메시지 또는 NULL 메시지를 받는 방식.

send와 receive가 모두 봉쇄형이면 송신자와 수신자 사이에 랑데부가 발생.

생산자와 소비자 문제의 해결책도 봉쇄형 send와 receive를 사용하여 단순화 가능.

 

버퍼링

통신이 직접적이든 간접적이든, 통신하는 프로세스들이 교환하는 메시지는 임시 큐에 들어감.

큐를 구현하는 방식은 무용량, 유한 용량, 무한 용량으로 구분.

무용량은 큐의 최대 길이가 0인 방식.

링크는 자체 안에 대기하는 메시지를 가질 수 없음.

송신자는 수신자가 메시지를 수신할 때까지 기다려야 함.

유한 용량은 큐가 유한한 길이 n을 가지는 방식.

최대 n개의 메시지가 큐에 들어갈 수 있음.

큐가 만원이 아니면 메시지는 큐에 놓이고 송신자는 대기하지 않고 실행을 계속.

큐가 만원이면 송신자는 큐 안에 공간이 이용 가능해질 때까지 봉쇄되어야 함.

무한 용량은 큐가 잠재적으로 무한한 길이를 가지는 방식.

메시지는 얼마든지 큐 안에서 대기 가능.

송신자는 절대 봉쇄되지 않음.

무용량의 경우는 버퍼가 없는 메시지 시스템.

다른 경우들은 자동 버퍼링.

 




IPC 시스템의 사례

대표적인 IPC 시스템에는 POSIX 공유 메모리 API, Mach 운영체제의 메시지 전달, Windows IPC 기법, 파이프가 있음.

 

POSIX 공유 메모리

POSIX 공유 메모리는 메모리-사상 파일을 사용하여 구현.

POSIX 공유 메모리를 사용하려면 먼저 shm_open 시스템 콜로 공유 메모리 객체 생성.

공유 메모리 객체 이름, 생성 옵션, 읽기/쓰기 권한을 지정.

객체가 생성되면 파일 설명자를 반환.

그다음 ftruncate 함수를 사용하여 객체의 크기를 바이트 단위로 설정.

그 후 mmap 함수를 사용하여 공유 메모리 객체를 포함하는 메모리-사상 파일을 주소 공간에 매핑.

MAP_SHARED 플래그는 공유 메모리에 대한 변경이 해당 객체를 공유하는 모든 프로세스에 보이도록 함.

생산자는 공유 메모리에 문자열을 쓰고, 소비자는 같은 공유 메모리 객체를 열어 내용을 읽음.

소비자 프로세스는 공유 메모리의 내용을 읽은 뒤 shm_unlink 함수를 호출하여 공유 메모리 객체를 제거.

 

Mach 메시지 전달

Mach 운영체제는 메시지 전달 중심으로 설계.

Mach는 분산 시스템용으로 설계되었지만 macOS와 iOS 운영체제에도 포함.

Mach에서 포트는 메일박스처럼 동작.

포트는 크기가 정해져 있고 단방향.

양방향 통신의 경우 메시지가 한 포트로 전송되고 응답이 별도의 응답 포트로 전달되는 방식.

각 포트에는 여러 송신자가 있을 수 있지만 수신자는 오직 하나의 태스크.

Mach는 포트를 사용하여 태스크, 스레드, 메모리, 프로세서 같은 자원을 나타냄.

포트에는 포트 권한이라는 개념이 연결.

태스크가 포트에서 메시지를 수신하려면 해당 포트에 대한 수신 권한 필요.

포트를 생성한 태스크는 해당 포트의 소유자가 되며 수신 권한을 소유.

부트스트랩 포트는 시스템 전체의 부트스트랩 서버에 등록된 포트를 검색할 수 있게 함.

Mach 메시지는 고정 크기 메시지 헤더와 가변 크기 본체를 포함.

메시지 헤더는 메시지 크기, 소스 포트, 대상 포트 정보를 포함.

가변 크기 본체는 데이터를 포함.

단순 메시지는 커널에 의해 해석되지 않는 구조화되지 않은 사용자 데이터를 포함.

복잡한 메시지는 out-of-line 데이터 포인터를 포함할 수 있음.

mach_msg 함수는 메시지를 보내고 받는 표준 API.

송신 또는 수신 여부는 MACH_SEND_MSG 또는 MACH_RCV_MSG 값으로 지정.

 

Windows

Windows는 다중 운영 환경 또는 서브시스템을 지원.

응용 프로그램은 메시지 전달 방식으로 서브시스템 서버와 통신.

Windows 메시지 전달 설비는 고급 로컬 프로시저 호출 설비, ALPC(Advanced Local Procedure Call).

ALPC는 같은 기계상의 두 프로세스 간 통신에 사용.

Windows는 두 프로세스 간 연결을 구축하고 유지하기 위해 포트 객체 사용.

연결 포트와 통신 포트 두 유형의 포트 사용.

서버 프로세스는 모든 프로세스가 접근할 수 있는 연결 포트 객체를 공개.

클라이언트가 서비스 요청을 원하면 서버의 연결 포트에 대한 핸들을 열고 연결 요청을 보냄.

서버는 채널을 생성하고 핸들을 클라이언트에 반환.

채널은 한 쌍의 사적 통신 포트로 구성.

작은 메시지는 포트의 메시지 큐를 통해 전달.

대용량 메시지는 섹션 객체를 통해 전달되어야 함.

데이터 양이 너무 많아 섹션 객체도 피해야 할 경우, 

서버 프로세스가 클라이언트의 주소 공간을 직접 읽거나 쓸 수 있는 API 사용 가능.

ALPC는 Windows API의 일반 공개 부분이 아니므로 일반 응용 프로그램에서는 직접 사용 불가.

 


파이프

파이프는 두 프로세스가 통신할 수 있게 하는 전달자로 동작.

파이프는 초기 UNIX 시스템에서 제공한 IPC 기법 중 하나.

파이프 구현에서 고려할 문제는 단방향 또는 양방향 통신, 

반이중 또는 전이중 통신, 부모-자식 관계 필요 여부, 네트워크 통신 지원 여부.

일반 파이프는 생산자-소비자 형태로 두 프로세스 간 통신을 허용.

생산자는 파이프의 쓰기 종단에 쓰고, 소비자는 읽기 종단에서 읽음.

일반 파이프는 한쪽으로만 데이터를 전송하는 단방향 통신.

양방향 통신이 필요하면 두 개의 파이프를 사용해야 함.

UNIX에서 일반 파이프는 pipe 함수를 사용하여 생성.

fd[0]은 파이프의 읽기 종단.

fd[1]은 파이프의 쓰기 종단.

UNIX는 파이프를 특수 유형 파일로 취급하므로 read와 write 시스템 콜을 통해 접근 가능.

일반 파이프는 부모 프로세스가 생성하고 fork로 생성한 자식 프로세스와 통신하기 위해 자주 사용.

Windows 시스템의 일반 파이프는 익명 파이프라고 부름.

Windows 익명 파이프는 ReadFile과 WriteFile을 사용하여 읽고 쓰는 구조.

지명 파이프는 일반 파이프보다 강력한 통신 도구.

지명 파이프는 양방향 통신 가능.

부모-자식 관계도 필요 없음.

여러 프로세스가 이름을 사용하여 지명 파이프에 접근 가능.

지명 파이프는 통신 프로세스가 종료되더라도 계속 존재 가능.

UNIX에서 지명 파이프는 FIFO라고 부름.

FIFO는 파일 시스템의 보통 파일처럼 존재.

mkfifo 시스템 콜로 생성되고, open, read, write, close 같은 일반 파일 접근 방식으로 사용 가능.

Windows의 지명 파이프는 UNIX의 FIFO보다 풍부한 통신 기법 제공.

전이중 통신 허용.

통신 프로세스들은 같은 기계 또는 다른 기계에 존재 가능.

CreateNamedPipe 함수로 생성하고, ConnectNamedPipe 함수로 연결.

ReadFile과 WriteFile 함수로 데이터 송수신.

 


 


클라이언트-서버 환경에서 통신

공유 메모리와 메시지 전달 기법은 클라이언트-서버 시스템 통신에도 사용 가능.

클라이언트-서버 환경에서는 소켓과 원격 프로시저 호출이 대표적인 통신 방식.

 

소켓

소켓은 통신의 극점 또는 끝점을 의미.

두 프로세스가 네트워크상에서 통신하려면 양 프로세스마다 하나씩, 총 두 개의 소켓 필요.

각 소켓은 IP 주소와 포트 번호 두 가지를 결합하여 구별.

서버는 지정된 포트에서 클라이언트 요청 메시지가 도착하기를 기다림.

1024 미만 포트는 well-known 포트로 사용되는 경우가 많음.

SSH 서버는 포트 22, FTP 서버는 포트 21, HTTP 서버는 포트 80에서 요청을 수신하는 식.

클라이언트가 연결을 요청하면 호스트 컴퓨터가 보통 1024보다 큰 임의의 포트 번호를 부여.

모든 연결은 유일한 소켓 쌍으로 구성됨.

Java는 연결 기반 TCP 소켓, 비연결 UDP 소켓, 멀티캐스트 소켓을 제공.

TCP 소켓은 Socket 클래스로 구현.

UDP 소켓은 DatagramSocket 클래스로 구현.

MulticastSocket은 데이터그램을 여러 수신자에게 보낼 때 사용.

Date 서버 예시에서는 서버가 포트 6013을 listen.

ServerSocket을 생성하고 accept 메서드로 클라이언트 연결을 기다림.

클라이언트는 Socket을 생성하고 IP 주소 127.0.0.1과 포트 6013의 서버에 연결.

127.0.0.1은 루프백 주소로 자기 자신을 가리키는 주소.

소켓 통신은 분산 프로세스 간 통신에 널리 사용되고 효율적이지만 낮은 수준.

소켓은 구조화되지 않은 바이트 스트림만 통신하므로, 

데이터를 구조화하고 해석하는 책임은 클라이언트와 서버에게 있음.

 

원격 프로시저 호출

원격 프로시저 호출은 분산 시스템에서 프로세스 사이의 절차 호출 기법을 추상화한 방법.

RPC(Remote Procedure Call)는 원격 시스템의 프로시저를 마치 로컬 프로시저처럼 호출하도록 하는 구조.

RPC는 클라이언트 쪽에 스텁을 제공하여 통신을 숨김.

클라이언트가 원격 프로시저를 호출하면 RPC는 해당 스텁을 호출.

클라이언트 스텁은 원격 프로시저가 필요로 하는 매개변수를 찾아 정돈하고 메시지로 만듦.

이 과정을 매개변수 정렬 marshalling이라고 함.

서버 쪽 스텁은 메시지를 받아 매개변수를 풀고 실제 서버 프로시저를 호출.

결과도 같은 방식으로 다시 클라이언트에게 반환.

Windows 시스템에서는 스텁 코드가 MIDL(Microsoft Interface Definition Language)로 작성된

명세로부터 컴파일됨.

매개변수 정돈은 클라이언트와 서버의 데이터 표현 차이를 해결하기 위한 작업.

서로 다른 기계는 바이트 순서가 다를 수 있음.

big-endian은 최상위 바이트를 먼저 저장하는 방식.

little-endian은 최하위 바이트를 먼저 저장하는 방식.

데이터 표현 차이를 해결하기 위해 외부 데이터 표현 방식인 XDR 사용 가능.

RPC에서는 네트워크 오류로 인한 실패 가능성도 고려해야 함.

운영체제는 메시지가 최대 한 번 실행되는지, 정확히 한 번 실행되는지에 대한 의미를 보장해야 함.

최대 한 번 의미는 요청 메시지가 한 번만 처리되도록 보장하는 방식.

정확히 한 번 의미는 서버가 요청을 받지 못하는 위험까지 제거할 필요가 있음.

RPC에서 또 중요한 문제는 클라이언트가 서버 포트 번호를 알아야 한다는 점.

해결 방법 중 하나는 고정 포트 사용.

다른 방법은 matchmaker 또는 포트 매퍼 사용.

서버는 시작 시 RPC 이름과 포트 번호를 matchmaker에 등록.

클라이언트는 RPC 이름을 matchmaker에 보내고 해당 포트 번호를 알아낸 뒤 요청을 보냄.

 

Android RPC

Android 운영체제는 바인더 프레임워크를 통한 IPC 기법을 제공.

Android의 RPC는 프로세스가 다른 프로세스의 서비스를 요청할 수 있게 하는 방식.

클라이언트는 bindService를 호출하여 서비스에 바인딩.

바인딩된 서비스는 onBind 메서드를 통해 클라이언트에게 메시지를 보낼 수 있는 인터페이스 제공.

Messenger 서비스는 단방향 통신 가능.

서버가 클라이언트에게 응답해야 하면 클라이언트는 Messenger 서비스를 제공해야 함.

RPC를 제공하기 위해 onBind 메서드는 

클라이언트가 서비스와 상호작용할 수 있는 원격 오브젝트 안의 메서드를 정의하는 인터페이스를 반환해야 함.

이 인터페이스는 AIDL로 작성됨.

AIDL은 Android Interface Definition Language.

Android 개발 키트는 AIDL 파일에서 Java 인터페이스와 서비스의 RPC 인터페이스 역할을 하는 스텁 생성.

내부적으로 Android 바인더 프레임워크는 매개변수 정돈,

프로세스 사이의 정돈된 매개변수 전달, 필요한 서비스 구현 호출, 반환 값 전달을 처리.

저작자표시 비영리 변경금지 (새창열림)

'개인공부 > OS' 카테고리의 다른 글

스레드와 병행성  (0) 2026.06.02
CPU 스케줄링  (0) 2026.06.02
운영체제 구조  (0) 2026.05.25
'개인공부/OS' 카테고리의 다른 글
  • 스레드와 병행성
  • CPU 스케줄링
  • 운영체제 구조
heishooni@gmail.com
heishooni@gmail.com
Linux, Cloud, Network 핵심 이론과 실무 구축 과정을 기록합니다. 인프라 엔지니어를 지향하는 기술 블로그이자 트러블 슈팅 저장소입니다.
  • heishooni@gmail.com
    heishooni
    heishooni@gmail.com
  • 전체
    오늘
    어제
    • 분류 전체보기 N
      • Network
      • Infra
      • 개인공부 N
        • network
        • OS N
        • 자료구조
        • Java
      • TroubleShooting
      • Personal
  • 블로그 메뉴

    • 홈
    • 방명록
  • 공지사항

  • 인기 글

  • 최근 글

  • 링크

    • https://github.com/heishooni
    • https://hooni.nangman.cloud/
  • 태그

    zsh
    bgp hijacking
    AWS Summit
    CML
    network
    Infra
    homelab
    네트워크 #network #CGNAT
    hyperplane
    hushlogin
    WISOFT
    OS
    네트워크
    Protocol
    Stateful
    proxmox
    MacOS
    troubleshooting
    MTR
    opnsense
    WireGuard
    teleport
    KIRO
    Devian
    개발자 설정
    터미널 꾸미기
    Stateless
    ipsec
    NangmanInfra
    Last login
  • hELLO· Designed By정상우.v4.10.6
heishooni@gmail.com
프로세스
상단으로

티스토리툴바