1. Process

프로세스는 실행 중인 프로그램으로, 단순히 저장된 파일 형태의 프로그램과 다르다. 프로그램은 그저 디스크에 저장된 명령어 목록 (passive entity)일 뿐이지만, 실행되면 메모리에 올라가고 CPU가 이를 처리 (active entity)하면서 프로세스로 변한다. 예를 들어, 컴퓨터에 카카오톡이 설치되어 있다고 해도 실행하기 전까지는 단순한 파일에 불과하지만, 실행 버튼을 누르면 메모리에 로드되면서 프로세스가 되어 CPU와 메모리 등의 자원을 사용하게 된다. 프로세스는 프로그램 카운터를 통해 어떤 명령을 실행할지 관리하며, 운영체제가 이를 제어한다.
1.1 Process in Memory
Memory Layout

메모리 레이아웃: 프로세스가 실행될 때 메모리에서 특정 구조로 구성됨
- 텍스트 영역 (Text Section):
- 프로그램 코드 저장
- 실행할 명령어 포함
- 데이터 영역 (Data Section):
- 전역 변수 저장
- 초기화된 변수 → 초기화된 데이터 영역
- 초기화되지 않은 변수 → BSS(Uninitialized Data Section)
- 스택 영역 (Stack Section):
- 함수 호출 시 필요한 임시 데이터 저장
- 함수 매개변수, 반환 주소, 지역 변수 포함
- 힙 영역 (Heap Section):
- 실행 도중 동적 메모리 할당 공간
- malloc()이나 new를 사용해 크기 변동 가능
Example C Program

C 프로그램이 실행되면, 프로세스의 메모리는 여러 영역으로 나뉘어 관리된다. 텍스트 영역(Text Section)에는 프로그램의 코드가 저장되며, 실행 중에 CPU가 이 코드를 참조한다. 데이터 영역(Data Section)에는 전역 변수가 저장되는데, 초기화되지 않은 변수 x는 BSS 영역(uninitialized data section)에, 초기화된 변수 y는 초기화된 데이터 영역(initialized data section)에 위치한다. 스택 영역(Stack Section)은 함수 실행에 필요한 공간으로, main() 함수의 매개변수 argc, argv와 지역 변수 values, i 등이 저장된다. 힙 영역(Heap Section)은 실행 중 동적으로 할당되는 공간으로, malloc()이나 new를 사용해 메모리를 할당하면 해당 데이터가 이 영역에 저장된다.
예를 들어, values가 malloc()을 통해 메모리를 할당받으면, values 자체는 스택에 저장되지만, 실제 할당된 데이터는 힙 영역에 위치한다. 쉽게 말해, values는 "주소를 적어둔 메모장"이고, 힙 영역은 "실제 데이터가 보관된 창고"와 같다. 이러한 구조 덕분에 프로그램은 실행 중에도 필요한 만큼 메모리를 효율적으로 관리할 수 있다.
Process State

프로세스는 실행되는 동안 여러 상태로 변화한다. 처음 프로세스가 생성될 때는 New(생성) 상태이며, 운영체제가 프로세스를 준비하는 단계이다. 이후 CPU에서 실행되면 Running(실행 중) 상태가 되며, 명령어들이 수행된다. 하지만 프로세스가 어떤 이벤트(예: 파일 읽기, 네트워크 응답)를 기다려야 할 경우 Waiting(대기) 상태로 전환된다. 반면, 실행할 준비는 되었지만 아직 CPU를 할당받지 못한 경우 Ready(준비 완료) 상태에 놓인다. CPU가 사용 가능해지면 Ready 상태의 프로세스가 Running 상태로 바뀌어 실행된다. 마지막으로, 프로세스가 모든 작업을 마치면 Terminated(종료) 상태가 되어 운영체제에서 정리된다.
예를 들어, 사용자가 텍스트 편집기를 실행하면 먼저 New 상태로 시작되고, 실행되면서 Running 상태가 된다. 사용자가 파일을 열어야 한다면, 파일이 로드될 때까지 Waiting 상태로 전환된다. 만약 여러 프로그램이 실행 중이라 CPU가 바쁘다면, 편집기는 Ready 상태에서 CPU 할당을 기다릴 수도 있다. 파일을 다 편집하고 프로그램을 종료하면 Terminated 상태가 되어 프로세스가 완전히 종료된다.

Process Control Block (PCB)
운영체제는 실행 중인 프로세스를 관리하기 위해 프로세스 제어 블록(PCB, Process Control Block)을 사용한다. PCB는 프로세스의 상태, 실행 중인 코드 위치, 할당된 자원 등의 정보를 저장하는 데이터 구조로, 운영체제가 프로세스를 효율적으로 관리할 수 있도록 돕는다.

PCB에는 프로세스 상태(실행 중, 대기 중 등), 프로그램 카운터(다음 실행할 명령어의 위치), CPU 레지스터 정보, CPU 스케줄링 정보(우선순위, 대기 큐 정보), 메모리 관리 정보(할당된 메모리 영역), 회계 정보(CPU 사용 시간, 실행 시간 제한), I/O 상태 정보(할당된 입출력 장치, 열린 파일 목록) 등이 포함된다. 예를 들어, 운영체제가 여러 개의 프로세스를 관리하는 공항의 항공 관제 시스템이라고 생각해 보자. PCB는 개별 항공기의 비행 상태(실행 중인지, 대기 중인지), 다음 목적지(프로그램 카운터), 조종석 상태(CPU 레지스터), 우선순위(이륙 순서), 할당된 활주로 및 공역(메모리 관리 정보), 비행 기록(회계 정보), 통신 장비 상태(I/O 정보) 등을 기록하는 비행 계획서와 같다. 이를 기반으로 운영체제는 프로세스를 적절히 스케줄링하고, CPU를 효율적으로 분배하며, 필요한 경우 프로세스를 멈추거나 다시 실행할 수 있다.
리눅스에서는 task_struct라는 구조체를 사용해 PCB를 구현하며, 여기에는 프로세스의 고유 식별자(t_pid), 현재 상태(state), 부모 프로세스(parent), 자식 프로세스 목록(children), 열린 파일 목록(files), 할당된 메모리 정보(mm) 등이 저장된다. 즉, 운영체제는 PCB를 활용해 각 프로세스를 개별적으로 관리하고, 필요할 때마다 정보를 확인하며, 실행 환경을 조정하는 역할을 수행한다.
1.2 Process Scheduling

프로세스 스케줄링(Process Scheduling)은 여러 프로세스 중에서 어떤 프로세스를 CPU에서 실행할지 결정하는 과정이다. 컴퓨터에서는 여러 개의 프로세스가 동시에 실행되지만, CPU 코어는 한 번에 하나의 프로세스만 실행할 수 있다. 따라서 운영체제는 프로세스 스케줄러를 이용해 실행 가능한 프로세스들 중 하나를 선택하고, 빠르게 전환하여 CPU 사용률을 극대화한다.

프로세스들은 실행 상태에 따라 다양한 대기 큐(Queue)에 배치된다. 준비 큐(Ready Queue)에는 실행할 준비가 되었지만 아직 CPU를 할당받지 못한 프로세스들이 있으며, 대기 큐(Wait Queue)에는 입출력(I/O) 작업이나 특정 이벤트를 기다리는 프로세스들이 포함된다. 운영체제는 준비 큐에 있는 프로세스들 중 하나를 선택하여 CPU에서 실행하고, 특정 작업이 끝나면 다시 준비 큐로 보내거나 종료시킨다. 예를 들어, 음악을 들으며 파일을 다운로드하고, 동시에 문서를 작성하는 상황을 생각해보자. 음악 재생 프로세스는 일정 간격으로 오디오 데이터를 처리하므로 잠깐씩 CPU를 사용했다가 대기하는 Ready Queue에 다시 들어간다. 파일 다운로드 프로세스는 네트워크 응답을 기다려야 하므로 Wait Queue에 들어가며, 문서 작성 프로그램은 사용자의 입력이 없으면 실행 대기 상태(Ready Queue)에 있다가, 키보드를 입력하면 CPU를 할당받아 실행된다.

운영체제는 이처럼 여러 프로세스를 빠르게 전환하여 실행하는데, 한 프로세스에서 다른 프로세스로 전환할 때 문맥 교환(Context Switch)이 발생한다. 이 과정에서 CPU는 현재 실행 중인 프로세스의 상태를 저장하고, 새롭게 실행할 프로세스의 상태를 불러온다. 이러한 스케줄링 덕분에 사용자들은 여러 프로그램을 동시에 실행할 수 있는 것처럼 보이지만, 실제로는 운영체제가 매우 빠르게 프로세스를 번갈아 실행하고 있는 것이다.
Context Switch
문맥 교환(Context Switch)은 CPU가 실행 중인 프로세스를 변경할 때 발생하는 과정이다. 컴퓨터에서는 여러 프로세스가 동시에 실행되는 것처럼 보이지만, 실제로 CPU는 하나의 프로세스를 실행하다가 다른 프로세스로 전환하면서 빠르게 번갈아 작업을 수행한다. 문맥 교환이 이루어질 때 운영체제는 현재 실행 중인 프로세스의 상태를 저장하고, 새로운 프로세스의 상태를 불러와야 한다. 이 과정에서 프로세스 제어 블록(PCB, Process Control Block)이 중요한 역할을 한다. PCB에는 프로세스의 상태, 프로그램 카운터, CPU 레지스터 값 등이 저장되며, 문맥 교환이 일어날 때 기존 프로세스의 정보를 PCB에 저장하고, 새 프로세스의 정보를 PCB에서 불러와 CPU가 이어서 실행할 수 있도록 한다.
그러나 문맥 교환은 순수한 오버헤드(pure overhead)로, CPU가 유용한 작업을 수행하는 것이 아니라 단순히 프로세스 전환을 위한 작업만 하므로 성능 저하의 원인이 될 수 있다. 운영체제가 복잡하거나 PCB에 저장해야 할 정보가 많을수록 문맥 교환 시간이 길어진다. 문맥 교환 속도는 하드웨어의 지원에 따라 달라질 수도 있다. 예를 들어, 일부 CPU는 여러 개의 레지스터 세트를 제공하여 한 번에 여러 개의 문맥을 저장할 수 있는데, 이를 하이퍼스레딩(Hyperthreading)이라고 한다. 하이퍼스레딩을 지원하는 CPU에서는 물리적인 코어 하나가 논리적으로 여러 개의 코어처럼 동작하여 문맥 교환을 줄이고 성능을 향상시킨다. 쉽게 말해, 문맥 교환은 CPU가 현재 작업을 임시 저장하고 새로운 작업으로 바꾸는 과정이다. 마치 여러 개의 앱을 빠르게 전환하는 스마트폰처럼, 운영체제는 프로세스를 번갈아 실행하며 사용자가 여러 작업을 동시에 수행할 수 있도록 한다. 하지만 앱을 전환할 때 약간의 로딩 시간이 필요한 것처럼, 문맥 교환도 성능에 영향을 미치는 중요한 요소다.
1.3 Operation on Processes
프로세스 종료(Process Termination)
프로세스는 마지막 명령을 실행한 후, 운영체제에 exit() 시스템 호출을 요청하여 종료된다. 종료될 때, 자식 프로세스(Child Process)는 자신의 상태 정보를 부모 프로세스(Parent Process)에게 전달하며(wait() 시스템 호출을 통해), 운영체제는 해당 프로세스가 사용하던 메모리 및 자원을 해제한다.
하지만 부모 프로세스는 abort() 시스템 호출을 사용해 강제로 자식 프로세스를 종료시킬 수도 있다. 예를 들어, 자식 프로세스가 할당된 메모리나 CPU 자원을 초과했거나, 더 이상 실행할 필요가 없는 작업을 수행하고 있거나, 부모가 먼저 종료되어 운영체제가 자식의 독립 실행을 허용하지 않는 경우 부모는 자식을 강제 종료할 수 있다. 특히, 일부 운영체제에서는 부모 프로세스가 종료되면 **자식 프로세스도 함께 종료되는 Cascading Termination(연쇄 종료)**을 수행한다. 즉, 부모가 종료되면 모든 자식 프로세스와 손자 프로세스까지 차례대로 종료된다.
운영체제는 wait() 시스템 호출을 통해 부모 프로세스가 자식 프로세스의 종료를 기다릴 수 있도록 한다. wait()을 호출하면 종료된 자식 프로세스의 상태 정보와 프로세스 ID(PID)를 반환받을 수 있다. 하지만 만약 부모가 wait()을 호출하지 않으면, **좀비 프로세스(Zombie Process)**가 발생한다. 좀비 프로세스는 실행을 완료했지만 부모가 종료 상태를 수거하지 않아서 프로세스 테이블에서 제거되지 않은 프로세스로, 불필요한 PID를 차지하며 시스템 리소스를 낭비할 수 있다.
반대로, 부모 프로세스가 먼저 종료되었지만 자식 프로세스가 계속 실행되는 경우, 해당 프로세스는 고아 프로세스(Orphan Process)가 된다. 고아 프로세스는 운영체제가 자동으로 init 프로세스(PID 1, 시스템의 루트 프로세스)에게 할당하여 관리하게 된다.
예제: 웹 브라우저와 다운로드 프로세스
예를 들어, 웹 브라우저(부모 프로세스)에서 파일 다운로드(자식 프로세스)를 실행한다고 가정하자.
- 사용자가 다운로드를 시작하면, **웹 브라우저(부모 프로세스)**가 fork()를 호출하여 **다운로드 프로세스(자식 프로세스)**를 생성한다.
- 다운로드가 진행되는 동안, 브라우저가 종료되더라도 다운로드가 계속되길 원한다면, 운영체제는 다운로드 프로세스를 고아 프로세스로 만들고 init 프로세스가 이를 관리하게 된다.
- 하지만 만약 브라우저가 abort()를 호출하여 강제로 다운로드 프로세스를 중단하면, 다운로드가 즉시 종료된다.
- 반면, 브라우저가 wait()을 호출하지 않고 종료되면 다운로드 프로세스는 좀비 프로세스가 되어 불필요한 리소스를 차지할 수 있다.
운영체제는 이러한 프로세스 종료 과정을 자동으로 관리하며, 부모-자식 프로세스 간의 관계를 유지하고 리소스를 효율적으로 정리하는 역할을 한다.
프로세스 간 통신(Interprocess Communication, IPC)
운영체제에서 실행되는 프로세스들은 서로 독립적으로 동작할 수도 있지만, **협력하는 프로세스(Cooperating Process)**가 되어 다른 프로세스와 데이터를 공유하거나 영향을 주고받을 수도 있다. 협력하는 프로세스들은 정보 공유(Information Sharing), 연산 속도 향상(Computation Speedup), 모듈화(Modularity), 편의성(Convenience) 등의 이유로 서로 통신할 필요가 있으며, 이를 위해 **프로세스 간 통신(IPC, Interprocess Communication)**이 필요하다.
예를 들어, 웹 브라우저와 다운로드 관리 프로그램을 생각해보자. 사용자가 웹 브라우저에서 파일을 다운로드하면, 다운로드 관리 프로그램이 실행되어 파일을 저장하는 작업을 담당한다. 이 과정에서 브라우저와 다운로드 관리 프로그램은 파일의 상태(다운로드 진행률, 남은 시간 등)를 공유해야 하므로 **프로세스 간 통신(IPC)**이 필요하다.
프로세스 간 통신 모델(IPC Models)
IPC에는 두 가지 주요 방식이 있다.
- 공유 메모리(Shared Memory)
- 두 프로세스가 특정 메모리 공간을 공유하여 데이터를 주고받는 방식이다.
- 운영체제가 직접 데이터를 주고받는 것이 아니라, **사용자 프로세스(User Process)**가 공유 메모리에 직접 접근하여 데이터를 읽고 쓴다.
- 문제점: 두 프로세스가 동시에 같은 메모리에 접근하면 데이터 충돌이 발생할 수 있으므로, 동기화(Synchronization) 메커니즘이 필요하다.
- 예제: 채팅 프로그램에서 메시지를 공유 메모리를 통해 전달하는 경우. 사용자가 메시지를 입력하면 공유 메모리에 저장하고, 상대방이 해당 메시지를 읽도록 동기화해야 한다.
- 메시지 전달(Message Passing)
- 프로세스 간 직접적인 메모리 공유 없이 **메시지(Message)**를 주고받는 방식이다.
- 운영체제의 IPC 시스템이 메시지를 전달하며, send(message)와 receive(message) 연산을 사용한다.
- 메시지 크기는 고정(Fixed) 또는 가변(Variable)일 수 있다.
- 예제: 이메일 서버에서 사용자가 이메일을 보내면, 서버는 send()를 사용해 메시지를 저장하고, 받는 사람이 receive()를 호출하여 메시지를 확인하는 방식이다.
메시지 전달 방식의 종류
메시지 전달 방식은 **물리적 연결(Physical)**과 **논리적 연결(Logical)**로 나뉜다.
- 물리적 연결(Physical)
- 공유 메모리(Shared Memory)
- 하드웨어 버스(Hardware Bus)
- 네트워크(Network)
- 논리적 연결(Logical)
- 직접(Direct) 또는 간접(Indirect, Mailbox 사용): 프로세스가 서로 직접 메시지를 주고받거나, 특정 메일박스를 통해 메시지를 주고받는 방식이다.
- 동기(Synchronous) 또는 비동기(Asynchronous): 메시지를 보낼 때 즉시 응답을 받는 방식(동기)과, 응답을 기다리지 않고 바로 다음 작업을 수행하는 방식(비동기)이 있다.
- 자동 버퍼링(Automatic Buffering) 또는 명시적 버퍼링(Explicit Buffering): 메시지를 저장할 때 자동으로 운영체제가 버퍼를 할당하는 방식과, 프로그래머가 직접 버퍼를 관리하는 방식이있다.
IPC 방식 비교
공유 메모리(Shared Memory) | 프로세스가 직접 메모리 공간을 공유하여 데이터 교환 | 속도가 빠르고 효율적 | 동기화가 필요하며 데이터 충돌 가능성 존재 |
메시지 전달(Message Passing) | 운영체제가 메시지를 관리하며 주고받음 | 프로세스 간 직접 공유 메모리 없이 안전하게 통신 가능 | 속도가 상대적으로 느릴 수 있음 |
예제: 게임 서버에서 IPC 활용
온라인 게임을 예로 들면, 게임 서버는 **공유 메모리(Shared Memory)**를 사용해 여러 플레이어의 좌표 데이터를 저장하고, 게임 클라이언트가 이를 실시간으로 읽는다. 동시에, **메시지 전달(Message Passing)**을 사용하여 채팅 기능을 구현할 수 있다. 플레이어가 메시지를 입력하면 send()를 통해 서버에 전달되고, 다른 플레이어가 receive()를 사용하여 해당 메시지를 확인하는 방식이다.
이처럼 운영체제는 공유 메모리와 메시지 전달 방식을 적절히 조합하여 프로세스 간 원활한 통신을 보장하며, 프로그램의 성능과 안정성을 높이는 역할을 한다.
'Computer Scinece > Computer Architecture & OS' 카테고리의 다른 글
Operating System [1]: 운영 체제 구조 (Operating System Structures) (0) | 2025.03.05 |
---|---|
Digital Design [1] : 디지털 시스템 (0) | 2025.03.05 |