운영체제

Processes, Scheduling, fork()

gyujin77 2025. 3. 24. 21:54
1. 프로세스 (Process)란?
실행 중인 프로그램을 의미함.

프로그램(코드) + 실행 중인 데이터(메모리 상태) 를 포함함.

운영체제에서 Job(작업) = Process(프로세스) 로 다룸.

2. 프로세스의 데이터 구조 (Process Data Structure)
프로세스 정보를 저장하는 데이터 구조가 필요함.

운영체제는 이를 이용해 문맥 교환(Context Switching) 을 수행함.

3. 문맥 교환 (Context Switching)
CPU가 실행 중인 프로세스를 다른 프로세스로 전환하는 과정.

현재 프로세스의 상태(레지스터, 프로그램 카운터 등)를 저장하고,
새 프로세스의 저장된 상태를 불러와 실행하는 방식.

멀티태스킹 환경에서 필수적으로 사용됨.

➡ 결론: 프로세스는 실행 중인 프로그램이며, 문맥 교환을 통해 여러 프로세스를 효율적으로 실행할 수 있음! 🚀

>>>>

1. 프로세스 식별 정보 (Process Identification)
운영체제에서 프로세스를 관리하기 위해 사용하는 식별 정보.

Process Identifier (PID): 각 프로세스에 부여되는 고유한 ID.

Parent Process Identifier (PPID): 부모 프로세스의 ID.

User Identifier (UID): 프로세스를 실행한 사용자의 ID.

2. 프로세서 상태 정보 (Processor State Information)
프로세스가 실행될 때 CPU가 관리하는 정보.

User-visible registers: 사용자 프로그램이 직접 접근할 수 있는 레지스터.

Control and status registers: 제어 및 상태를 저장하는 레지스터 (예: 프로그램 카운터).

Stack pointers: 함수 호출 및 반환 시 사용되는 스택의 위치를 가리키는 포인터.

3. 프로세스 제어 정보 (Process Control Information)
운영체제가 프로세스를 관리하기 위해 저장하는 정보.

Process state: 실행 중, 대기 중, 중지됨 등의 상태 정보.

Memory pointers: 해당 프로세스가 사용하는 메모리 주소 정보.

Interprocess communication (IPC): 다른 프로세스와의 통신 관련 정보.

➡ 결론: 프로세스는 다양한 식별 정보와 상태 정보를 가지고 있으며, 운영체제는 이를 기반으로 프로세스를 관리하고 스케줄링함! 🚀

>>>>>>>>>>>>

PCB (Process Control Block) - 운영체제가 프로세스를 표현하는 방법
운영체제는 PCB(Process Control Block, 프로세스 제어 블록) 를 통해 프로세스를 관리함.
PCB는 프로세스의 상태와 관련된 중요한 정보를 저장하는 데이터 구조임.

📌 PCB에 포함된 정보
프로세스 상태 (Process State)

실행 중(Running), 준비(Ready), 대기(Waiting) 등의 현재 상태 정보

프로세스 식별자 (Process Identifier, PID)

프로세스를 구별하는 고유한 번호

부모 프로세스 ID (PPID)도 포함됨

프로그램 카운터 (Program Counter, PC)

현재 실행 중인 명령어의 메모리 주소 저장

문맥 교환(Context Switching) 시 프로세스를 다시 실행할 위치를 결정

CPU 레지스터 (CPU Registers - Context)

실행 중인 프로세스의 레지스터 값 (일반 레지스터, 스택 포인터, 프로그램 카운터 등)

CPU 스케줄링 정보 (CPU Scheduling Information)

우선순위, 스케줄링 큐 위치 등 프로세스 스케줄링을 위한 정보

메모리 관리 정보 (Memory Management Information)

페이지 테이블, 세그먼트 테이블, 메모리 할당 정보 등

회계 정보 (Accounting Information)

CPU 사용 시간, 실행 시간, 프로세스 생성 시간 등 성능 측정 정보

입출력 상태 정보 (I/O Status Information)

열린 파일 목록, 할당된 입출력 장치 정보 등

💡 PCB의 역할
✅ 운영체제가 프로세스를 관리하고 추적하는 핵심 데이터 구조
✅ 문맥 교환(Context Switching) 시 프로세스 상태를 저장하고 복원
✅ 프로세스 스케줄링과 메모리 관리 최적화에 사용됨

➡ PCB는 운영체제가 프로세스를 효과적으로 관리하는 핵심 요소! 🚀

>>>>>>>>>>

문맥 교환(Context Switching) 과정 설명
위 그림은 운영체제가 프로세스 간 전환(Context Switching) 을 수행하는 과정을 나타냄.
즉, 하나의 프로세스를 중단하고 다른 프로세스를 실행하는 과정임.

🔹 문맥 교환 과정 (Context Switching Steps)
프로세스 P₀ 실행 중 (executing)

P₀이 CPU에서 실행되고 있음.

그러다 인터럽트 발생 또는 시스템 호출이 일어남.

P₀의 상태 저장 (save state into PCB₀)

현재 실행 중이던 P₀의 레지스터, 프로그램 카운터(PC) 등의 상태를 PCB₀에 저장

이후 디스패처(dispatcher, 커널의 일부) 가 개입하여 다음 실행할 프로세스를 결정

P₁의 상태 복원 (reload state from PCB₁)

이전에 저장된 P₁의 PCB 정보를 복원

P₁이 CPU를 점유하고 실행 시작

P₁ 실행 (executing)

P₁이 실행됨

이후 또다시 인터럽트 발생 또는 시스템 호출이 일어남

P₁의 상태 저장 (save state into PCB₁)

현재 실행 중이던 P₁의 상태를 PCB₁에 저장

P₀의 상태 복원 (reload state from PCB₀)

이전에 저장된 P₀의 PCB 정보를 복원

P₀가 다시 실행됨

🔹 문맥 교환의 핵심 포인트
✅ 운영체제는 PCB를 사용하여 프로세스 상태를 저장하고 복원
✅ 인터럽트 또는 시스템 호출 시 문맥 교환이 발생
✅ 디스패처(dispatcher) 가 어떤 프로세스를 실행할지 결정
✅ 문맥 교환에는 오버헤드가 발생 (CPU는 유용한 작업을 하지 않고 상태를 저장/복원하는데 자원을 소비)

➡ 운영체제는 CPU 자원을 효율적으로 활용하기 위해 문맥 교환을 최소화해야 함! 🚀

>>>>>>>>>>

🔹 상태 전이 과정 (State Transition Steps)
Enter (프로세스 생성)

새로운 프로세스가 생성되면 Not Running (대기 상태) 에 들어감.

Dispatch (스케줄링되어 실행됨)

CPU 스케줄러가 해당 프로세스를 선택하면 실행 상태(Running)로 전이.

Pause (일시 중지 / 대기 상태로 복귀)

실행 중이던 프로세스가 I/O 작업 또는 CPU 할당이 끝나면 다시 Not Running 상태로 전이됨.

Exit (프로세스 종료)

실행이 완료된 프로세스는 시스템에서 제거됨.

>>>>>>>

🔹 프로세스 큐잉 다이어그램 (Queuing Diagram) 설명
이 다이어그램은 운영체제(OS)에서 프로세스가 CPU에 의해 처리되는 과정을 나타냄.

🔹 주요 구성 요소
Queue (대기열)

실행을 기다리는 여러 프로세스가 큐에 저장됨.

큐의 각 칸이 개별 프로세스를 의미.

프로세스는 순차적으로 CPU의 할당을 기다림.

Dispatch (할당)

CPU 스케줄러가 큐에서 프로세스를 선택하여 CPU에 할당.

이 과정을 Dispatch(디스패치)라 함.

Processor (CPU)

디스패처에 의해 선택된 프로세스가 CPU에서 실행됨.

실행이 끝나면 Exit(종료)되거나 다시 Queue로 돌아감.

Pause (대기 상태로 복귀)

입출력(I/O) 작업이 필요하거나, CPU 시간이 종료되면 다시 대기 큐로 돌아감.

Exit (종료)

프로세스가 모든 작업을 완료하면 시스템에서 제거됨.

🔹 핵심 개념
✔ 프로세스는 큐에서 대기하다가 CPU에서 실행됨.
✔ CPU에서 실행 후, 완료되지 않으면 다시 큐로 돌아갈 수 있음.
✔ 운영체제는 스케줄러를 이용해 CPU 할당을 조정함.
✔ 작업이 끝난 프로세스는 Exit(종료) 상태로 이동함.

➡ 운영체제는 이러한 큐잉 시스템을 활용하여 다중 프로세스를 효율적으로 관리함! 🚀

>>>>>>>>>>>>>>>>

New → Ready (Admitted)

새로 생성된 프로세스가 운영체제의 승인을 받아(Admitted) Ready 상태로 이동합니다.

Ready Queue(준비 큐)에서 FIFO(First In First Out) 방식으로 대기할 수 있음이 표시되어 있습니다.

Ready → Running (Dispatch)

스케줄러가 CPU를 할당하면 Ready 상태에서 Running 상태로 이동합니다.

CPU 개수만큼만 동시에 실행될 수 있습니다.

Running → Waiting (Wait for I/O or Event)

자발적 상태 변화로, 프로세스가 I/O 작업을 수행해야 하거나 특정 이벤트를 기다려야 하는 경우 발생합니다.

예시: sleep(1000)처럼 명시적으로 잠깐 멈추는 경우 포함.

Running → Ready (Timeout)

강제적 상태 변화로, CPU를 너무 오래 사용한 프로세스가 일정 시간(Time Slice)을 초과하면 Ready 상태로 돌아갑니다.

이는 시분할(Time-sharing) 스케줄링에서 CPU를 여러 프로세스가 공정하게 나누기 위한 방식입니다.

Waiting → Ready (I/O or Event Occur)

I/O 작업이 완료되거나 기다리던 이벤트가 발생하면 Ready 상태로 이동합니다.

CPU를 바로 할당받지는 않으며, Ready Queue에서 다시 대기합니다.

Running → Terminated (Exit)

프로세스가 실행을 끝내면 종료됩니다.

✅ 자발적 상태 변화:

Running → Waiting (I/O 또는 sleep 같은 이벤트 대기)

✅ 강제적 상태 변화:

Running → Ready (CPU 사용 시간 초과로 인해 강제 반환)

>>>>>>>>>>>

📌 Process Scheduling (프로세스 스케줄링)
운영체제에서 프로세스 스케줄링은 **CPU 사용률을 극대화하고, 빠르게 프로세스를 전환하여 타임 쉐어링(Time-sharing)**을 구현하는 역할을 합니다.

Process Scheduler(프로세스 스케줄러)
실행 가능한 프로세스 중 다음에 CPU를 실행할 프로세스를 선택하는 역할
다양한 스케줄링 큐(Scheduling Queues)를 유지하며, 프로세스는 이 큐들 사이를 이동함.

주요 스케줄링 큐(Scheduling Queues)
운영체제는 여러 개의 대기열(Queue)을 유지하여 프로세스의 상태를 관리합니다.

Job Queue (작업 큐)

시스템 내 모든 프로세스의 집합.

새로 생성된 프로세스는 Job Queue에 추가됨.

Ready Queue (준비 큐)

메인 메모리에 로드된, 실행 준비가 완료된 프로세스들의 집합.

CPU를 받을 준비가 된 상태지만, 아직 CPU를 할당받지 못한 프로세스들이 포함됨.

스케줄러가 이 큐에서 프로세스를 선택하여 실행시킴.

Device Queue (디바이스 큐)

I/O 작업을 기다리는 프로세스들의 집합.

예: 프린터, 디스크, 네트워크 요청 등을 기다리는 프로세스들이 포함됨.

I/O 작업이 완료되면 Ready Queue로 이동.

프로세스의 큐 이동 (Process Migration)
프로세스는 여러 큐를 오가며 실행됨.

>>>>>>>>>>>>>>>>>>

1️⃣ 주요 구성 요소

New Process (새로운 프로세스)

새로운 프로세스가 생성되면 **Ready Queue (준비 큐)**로 들어감.

Ready Queue (준비 큐)

CPU를 사용할 준비가 된 프로세스들이 모여 있음.

CPU 스케줄러가 선택하면 CPU에 할당됨.

CPU (중앙처리장치)

Load_PCB(): 프로세스의 **PCB (Process Control Block)**을 로드하여 실행.

Save_PCB(): 실행 중인 프로세스가 중단될 경우 PCB를 저장하고 Ready Queue로 보냄.

Device & Device Queues (디바이스 & 디바이스 큐)

I/O 작업이 필요하면 프로세스가 **Device Queue (입출력 대기 큐)**로 이동.

입출력 작업이 끝나면 다시 Ready Queue로 이동.

**I/O Interrupts (입출력 인터럽트)**를 통해 CPU로 복귀.

Event Waiting (이벤트 대기 큐)

특정 이벤트(예: 파일 입출력 완료, 사용자 입력 등)를 기다리는 프로세스가 대기.

이벤트 발생 후 Ready Queue로 복귀.

Timer Interrupts (타이머 인터럽트)

CPU를 너무 오래 사용한 프로세스를 강제로 Ready Queue로 이동시키는 역할.

**시분할 스케줄링(Time-sharing Scheduling)**에서 사용됨.

Memory (메모리)

프로세스가 실행될 때 메모리에 로드됨.

Release Resources (자원 해제)

프로세스가 종료되면, 사용했던 자원(메모리, 파일 등)을 반환하고 제거됨.

2️⃣ 프로세스 흐름 (Queue 이동 경로)
새로운 프로세스(New Process) → Ready Queue

Ready Queue → CPU (실행 중)

CPU에서 다양한 상황에 따라 상태 변화

I/O 요청 발생 → Device Queue로 이동 → 입출력 완료 후 Ready Queue로 이동

이벤트 대기 필요 → Event Waiting Queue로 이동 → 이벤트 발생 후 Ready Queue로 이동

타이머 인터럽트 발생 → CPU에서 강제로 Ready Queue로 이동 (시분할 스케줄링 적용 시)

프로세스 종료 → Release Resources 후 제거

>>>>>>>>>>

Scheduler: determines the change of process state
스케줄러: 프로세스 상태 변경을 결정함

운영체제에서 **스케줄러(Scheduler)**는 프로세스의 상태 변화(예: 실행, 대기, 종료 등)를 결정하는 역할을 수행합니다.

long-term scheduler (or job scheduler)
장기 스케줄러 (또는 작업 스케줄러)

역할: 시스템에 들어오는 새로운 프로세스 중에서 실행할 프로세스를 선택하여 Ready Queue로 보냄.

Short-term scheduler (or CPU scheduler)
단기 스케줄러 (또는 CPU 스케줄러)

역할: Ready Queue에서 실행할 프로세스를 선택하여 CPU에 할당.

ometimes the only scheduler in a system
때때로 시스템에서 유일한 스케줄러일 수도 있음

일부 시스템(예: 단순한 운영체제)에서는 장기 스케줄러 없이 단기 스케줄러만 존재할 수도 있음.

예를 들어, 모든 프로세스가 즉시 메모리에 올라가면 장기 스케줄러가 필요 없고, 단기 스케줄러만 동작.

✅ 즉, 운영체제에서 스케줄러는 프로세스 상태를 조정하며, 일부 시스템에서는 단기 스케줄러가 유일한 스케줄러 역할을 수행할 수도 있다. 🚀

>>>>>>>>>>

Short-term scheduler is invoked very frequently
단기 스케줄러는 매우 자주 호출됨
🔹 실행할 프로세스를 빠르게 선택해야 하므로 자주 동작함.

When a process leaves CPU
프로세스가 CPU를 떠날 때
🔹 실행이 끝나거나 I/O 요청으로 인해 CPU를 반납할 때 발생함.

in milliseconds
밀리초 단위로
🔹 빠른 프로세스 전환을 위해 매우 짧은 시간 간격으로 동작함.

must be fast
빠르게 동작해야 함
🔹 스케줄러가 느리면 CPU가 유휴 상태가 되어 비효율적임.

Long-term scheduler is invoked very infrequently
장기 스케줄러는 매우 드물게 호출됨
🔹 프로세스를 메모리에 적재할 때만 동작하므로 실행 빈도가 낮음.

When a process leaves memory
프로세스가 메모리를 떠날 때
🔹 프로세스가 종료되거나 스왑될 때 새로운 프로세스를 로드함.

in seconds/minutes
초/분 단위로
🔹 자주 실행되지 않으므로 상대적으로 긴 시간 간격으로 동작함.

may be slow
느려도 괜찮음
🔹 실행 빈도가 낮아 최적화된 프로세스 선정을 위한 시간이 충분함.

Types of processes
프로세스의 유형

I/O-bound process – spends more time doing I/O
I/O 중심 프로세스 – 입출력 작업을 더 많이 수행함
🔹 CPU보다는 디스크, 네트워크 등의 I/O 작업을 많이 요구함.

CPU-bound process – spends more time doing computations
CPU 중심 프로세스 – 연산을 더 많이 수행함
🔹 데이터 연산, 계산 등의 작업을 주로 수행하며 CPU 점유율이 높음.

>>>>>>>>>>>>>>

📌 쉽게 설명!
이 그림은 **장기 스케줄러(LT-scheduler)**가 겪는 문제를 보여줘.

💡 I/O 중심 프로세스가 많으면 무슨 일이 생길까?
✅ CPU에서 실행되다가 금방 I/O 작업(파일 읽기, 네트워크 요청 등) 하려고 멈춤.
✅ 그래서 I/O 장치 큐가 꽉 차고, 프로세스들이 대기만 하게 됨.
✅ 반대로 CPU는 할 일이 별로 없어 놀고 있을 수도 있음.

➡ 결과: 시스템이 비효율적으로 동작해서 성능이 떨어짐! 🚨

👉 해결 방법?
CPU 작업을 오래하는 CPU 중심 프로세스와 적절히 섞어야 함! 🔄

📌 쉽게 설명!
이번에는 CPU 중심 프로세스가 많을 때 문제를 보여주는 그림이야!

💡 CPU 중심 프로세스가 많으면?
✅ CPU를 오랫동안 점유하면서 계산을 계속함.
✅ 하지만 다른 프로세스들이 CPU를 기다려야 해서 준비 큐(Ready Queue)가 가득 참.
✅ 반대로 I/O 장치는 할 일이 별로 없어서 한가함.

➡ 결과: 새로운 프로세스가 들어오면 대기 시간이 길어지고, 시스템이 느려질 수 있음! 🐌

👉 해결 방법?
I/O 작업이 많은 I/O 중심 프로세스와 적절히 섞어야 함!

>>>>>>>>>>>>>>>

이번 그림은 LT(장기) 스케줄러가 CPU 중심과 I/O 중심 프로세스를 적절히 섞었을 때의 모습이야!

💡 적절한 프로세스 배분의 효과
✅ CPU를 사용하는 프로세스와 I/O를 사용하는 프로세스가 균형을 이룸.
✅ CPU와 I/O 장치가 모두 적절히 활용되어 대기 시간이 줄어듦.
✅ 시스템이 전체적으로 원활하게 운영됨! 🚀

➡ 결론: CPU 중심 & I/O 중심 프로세스를 적절히 섞는 것이 가장 효율적! 🔄🔥

>>>>>>>>>>>>

💾 중간 스케줄링(Medium Scheduling) - 스와핑(Swapping)

✅ "메모리가 부족할 때" 사용하지 않는 프로세스를 디스크로 이동 → Swap Out
✅ 나중에 다시 실행해야 하면, 디스크에서 메모리로 가져옴 → Swap In

➡ 결론: 메모리를 효율적으로 관리하고, 시스템이 멈추지 않도록 하는 중요한 기술! 🔄🔥

>>>>>>>>>>>.

👨‍👦 프로세스 생성 (Process Creation)

✅ 부모 프로세스가 자식 프로세스를 만든다.
✅ 자식 프로세스도 또 다른 자식 프로세스를 만들 수 있다.
✅ 이렇게 하면 나무(Tree) 구조처럼 여러 프로세스가 연결된다. 🌳✨

>>>>>>>>>>

프로세스 식별 및 관리
일반적으로 프로세스는 **프로세스 식별자(PID)**를 통해 식별되고 관리됨. → 운영체제가 각 프로세스를 구별하기 위해 고유한 번호를 할당함.

리소스 공유
부모와 자식이 모든 자원을 공유할 수 있음. → 같은 메모리 공간, 파일 등을 함께 사용함.

자식이 부모의 일부 자원만 공유할 수 있음. → 특정한 파일이나 메모리 일부만 공유하도록 설정 가능함.

부모와 자식이 자원을 전혀 공유하지 않음. → 독립적인 실행 환경을 가짐.

실행 방식
부모와 자식이 동시에 실행될 수 있음. → 병렬적으로 동작하여 서로 영향을 주지 않음.

부모가 자식이 종료될 때까지 기다릴 수도 있음. → 부모가 wait()을 호출하면, 자식 프로세스가 끝날 때까지 대기함.

>>>>>>>>>>.

주소 공간
자식 프로세스는 부모의 복제본임. → 즉, 부모 프로세스의 코드와 데이터를 그대로 복사받음.

자식 프로세스는 새로운 프로그램을 로드할 수 있음. → 새로운 프로그램을 실행하면 기존의 복사본이 사라지고 새 코드가 실행됨.

UNIX 예시
fork 시스템 호출은 새로운 프로세스를 생성함. → 부모 프로세스를 복제하여 자식 프로세스를 만들고, 둘은 별도로 실행됨.

exec 시스템 호출은 기존 프로세스의 메모리 공간을 새로운 프로그램으로 교체함. → 기존 프로세스를 유지하면서, 실행 중인 프로그램만 교체함.

>>>>>>

fork() → 부모가 자식을 생성

자식(child)이 exec() 실행 → 새로운 프로그램 실행

자식이 exit()로 종료

부모가 wait() 호출 → 자식이 끝날 때까지 기다림

자식이 종료되면 wait()이 끝나고 부모 프로세스가 다시 실행(resumes)

>>>>>>>>>>>>>

exec() 함수군 설명*
execlp(), execvp(), execle(), execv(), execve()는 거의 동일

차이점: $PATH 사용 여부, 인자 전달 방식, 환경 변수 변경 여부

어떤 일이 일어나는가?

주어진 프로그램이 현재 프로세스를 대체하여 실행됨

실행에 실패하면 함수가 반환됨

>>>>>>>>>>>>>

wait() 함수 설명
pid_t wait(int *status)

부모 프로세스가 자식 프로세스가 종료될 때까지 대기(임의의 자식 프로세스)

자식 프로세스의 종료 상태(exit status)를 수집 가능

자식 프로세스의 PCB(Process Control Block)를 정리

pid_t waitpid(pid_t pid, int *status, int options)

특정 자식 프로세스를 기다릴 수 있음

비동기(Non-blocking) 모드로 설정 가능

부모가 wait()을 호출하지 않으면?

부모 프로세스가 먼저 종료되면:

모든 자식 프로세스는 **init 프로세스(pid=1)**가 입양

실행 중인 경우 → 고아 프로세스(orphan process)

실행 종료한 경우 → init이 정리(clean-up)

부모 프로세스가 종료되지 않고 wait()을 호출하지 않으면?

자식 프로세스는 좀비 프로세스(zombie process) 상태 유지

좀비 프로세스가 계속 쌓이면 시스템 리소스 낭비

>>>>>>>

좀 더 쉽게 설명하면:
자식 프로세스가 종료되면, 운영체제는 해당 프로세스의 종료 상태(exit status)와 정보를 남겨둠.

부모 프로세스가 wait() 또는 waitpid()를 호출하면, 운영체제는 이 정보를 부모에게 전달한 후 정리(clean-up)함.

그런데 부모 프로세스가 wait()을 호출하지 않으면, 자식 프로세스의 정보가 정리되지 않고 계속 남아 있음 → 이것이 바로 좀비 프로세스(zombie process)!

좀비 프로세스가 너무 많아지면, 프로세스 ID(pid) 자원이 낭비되고, 시스템이 비효율적으로 동작할 수 있음.