안녕하세요. 우당탕탕 개발일지 입니다. 수업 시간에 배운 내용 위주로 정리해서 올린 글입니다.
시험대비
1. 프로세스와 프로그램 개념
2. 자식이 먼저 종료된 경우 : 좀비 /부모가 먼저 종료된 경우 : 고아 (종료 과정까지 알아두기) →생명 주기 시험에 나옴.
4. PCB와 VMS
5. 다시 ready로 가는 3가지 경우
ch 3-1 프러세스 개요
프로세스와 프로그램
- 프로세스 : 프로그램이 메모리에 적재되어 *실행 중인 상태.
- 프로그램 : 저장매체 안에 있는 상태 / 실행 파일의 형태
* 실행 중 : cpu에 의해 현재 실행되고 있거나 준비 상태로 기다리거나 입출력 등올 인해 중단되어 cpu로 부터 실행을 대기 하는 모든 상태를 말함.
프로세스 특징
- 프로세스들 마다 독립적인 메모리 공간을 가짐.→다른 프로세스는 접근 못함.
- 실행 - 대기 -잠자기 - 대기 - 실행- 종료 (프로세스 생명주기)
- 프로세스의 모든 정보는 커널에 의해서 관리
- 자원 : 코드,데이터, 스택, 힙 공간
- 프로세스마다 고유 번호 (=PID)를 할당.
프로그램의 다중 인스턴스⭐️
: 프로그램 실행 시 마다 생성되는 독립된 프로세스들.
프로세스 관리 내용 : (모두 커널에 의해 이뤄짐)
-프로세스 생성
-실행
-일시 중단 & 재개
-정보 관리
-프로세스 통신
-프로세스 동기화
-프로세스 컨텍스트 스위칭
프로세스 주소 공간
= 사용자 공간 + 커널 공간
= 프로세스가 실행 중에 접근할 수 있도록 허용된 주소의 최대 범위
CPU 주소 공간 : 컴퓨터 내에 cpu가 접근 가능한 전체 메모리 공간. 크기는 cpu 주소 선의 갯수에 따라 결정.

→코드와 데이터 영역에 적재되고 나면 실행 중에는 크기가 변하지 않음.
- 사용자 공간 = 코드,데이터, 힙, 스택
- 커널 공간 =사용자 공간→ 시스템 호출 → 커널 코드 실행
특징
- 각 프로세서 마다 독립된 사용자 공간을 제공함.
- 시스템 전체에 하나의 커널 주소 공간이 있음.
- 모든 프로세스는 커널 주소 공간을 공유함.
Q 언제 사용자 공간/커널 공간을 사용할까? 예시
#include <stdio.h>
int main() {
printf("Hello\n");
return 0;
}
1) printf() : 사용자 공간
2) 화면에 쓰기위해서는 하드웨어 접근 필요 ! 시스템 콜
3) write() : 커널 공간
Q 사용자 공간내 영역을 어떻게 사용할까? 예시


→ 위에 예시에서 헷갈릴 수 있는게 d,c는 f()프레임의 공간이고 p와 b는 main() 프레임 공간이다.
process +vms (=virtual memory space)
⭐️ 중요! ) 프로세스 주소 공간은 가상공간(=논리 공간) | 프로세스가 사용하는 주소 = 가상주소
- 논리적 : 0번지부터 시작해서 연속적인 메모리에 형성 ⭐️중요!) 가상 공간은 항상 0번째부터 시작.
- 물리적(실제) : 코드, 데이터, 힙, 스택에 흩어져서(=분산되서 ) 저장됨
→ 가상주소 공간과 물리 주소 공간을 연결하는 매핑 테이블을 이용함.
ch 3-2 커널 프로세스 관리
프로세스 테이블 : 시스템의 모든 프로세스들을 관리하기 위한 표.
→ 구현 방식은 운영체제마자 다름. / 시스템(=컴퓨터 환경)에 1개씩 있음.
프로세스 제어 블록 (PCE) : 프로세스에 관한 정보를 저장하는 구조체
→ 프로세스당 하나씩 존재
→ 프로세스가 생성될때 만들어지고 종료되면 종료
→ 커널에 의해 관리
운영체제가 관리해야하는 핵심 : 프로세스 테이블과 PCB의 위치
→커널 영역,커널 코드만 액세스 가능.
상태정보는 PCB에 저장.

if 프로세스 == 사람
→ PCB는 주민등록증
→ PID는 주민등록번호
PCB에는 이런 정보들이 들어 있어요
- PID (프로세스 ID)
- 상태 (Running / Ready / Waiting / Zombie 등)
- 부모 PID (PPID)
- 사용한 자원, CPU 시간
- 종료 코드(exit code)
⭐️⭐️⭐️ 프로세스 생명주기와 상태 변이 (생명주기 그리는 거 시험문제 )_ 연습문제랑 엮어서 보기
<상태정보>
* 대기큐 와 준비큐
-대기큐 : 입출력이나 외부 이벤트를 기다림 [상태: Waiting 또는 Blocked]
-준비큐 : cpu를 기다림 [상태: ready]
**종료코드 : PCB에 위치함


1) new
-프로세스가 생성된 상태
- PCB에 NEW상태로 등록
new → ready : 실행 준비를 마치면
2) ready
-스케줄링을 기다리는 대기 상태.
-프로세스 준비 큐에서 대기(준비큐는 대기 장소이고 어떤 순서가 우선순위가 될진 OS가 정함)
ready → running : 스케줄링이 되면
3) running
-프로세스 CPU에 의해 실행되는 상태.
running → ready : 시분할 시스템에서 할당한 만큼의 시간(=타임 슬라이드)이 지나면 다시 ready의 준비큐 삽입 상태로 변경.
running → blocked : 프로세스가 입출력을 시핸하면 커널이 프로세스를 blocked로 만들고 대기 큐 삽입
4)Blocked=Wait
-프로세스가 자원을 요청하거나 입출력을 요청하고 완료를 기다리는 상태
blocked →ready : 입출력이 완료되면 다시 ready의 준비큐에 삽입
5) Terminated/Zombie = 자식 종료 & 부모 종료 X
-프로세스의 불완전 종료 상태.
자식 프로세스가 남긴 종료 코드(PCB에 있음)를 부모 프로세스가 읽어가지 않아 완전히 종료되지 않은 상태
6) Terminated/Out
-자식 프로세스가 종료 하면서 남긴 종료코드를 부모 프로세스가 읽어 완전히 종료된 상태.
-프로세스 테이블의 항목과 PCB가 전부 제거된 상태.
다시 ready로 가는 방법 3가지 ⭐⭐⭐
1. running → waiting → ready (I/0) : 입출력 완료시 인터럽트 발생
2. running → ready (TTS) : 시간 초과로 cpu 반납
3. running → ready (preemption) : 선접 스케줄링에 의해 cpu 뺏김.
오늘날 운영체제의 실행단위 : 스레드
- 프로세스 스테줄링은 사라지고 스레드 스케줄링함.
- ready 상대에서 스레드 중 실행시킬 스레드 선책함.
- 프로세스 : 스레드(thread)에게 공유 자원을 제공하는 컨테이너 역할로 변경됨.
Ch 3-3 프로세스 계층 구조
- #0 프로세스 =조상 프로세스 (부팅시 실행되는 최초의 프로세스) = 시스템 유휴 프로세스 #0 (=swapped/sched) 커널이 만든 | #1 (=init/systemd) 사용자 레벨 최상위
- 부모 프로세스 : 여러개의 자식 프로세스를 가질 수 있음 | wait() 시스템 호출을 통해 반드시 자식 프로세스의 종료 코드를 읽어야 함.
- 자식 프로세스 : 부모 프로세스에 의해 생성 (프로세스 생성은 시스템 호출로)
#0 , #1프로세스를 제외한 모든 프로세스는 부모 프로세스를 가짐.
fork() : 시스템 콜 함수 , 자식 프로세스의 생성.
exec(): 덮어 쓸때 사용 = 프로세스의 오버레이에서 사용.
→현재 프로세스의 종료를 알리는 시스템 호출 & 커널 코드 실행.
wait() : 부모가 자식 프로세스의 종료를 기다리고 확인. (종료대기).
※ 부모가 죽었으면 좀비 프로세스이고 다른 부모 프로세스로 입양시켜줘여함
exit() : 프로세스 종료 과정에서 사용.

프로세스 종료
- PCB에 종료 코드(종료 상태) 저장
- PCB에 프로세스 상태를 Terminated라고 표시
- 프로세스에 할당된 모든 메모리 반환 __※ 단 PCB와 프로세스 테이블은 제거 되지 않음. (부모 프로세스가 자식의 종료 상태를 읽어야 하기 때문. )
좀비 상태
- 종료 하였지만 부모가 종료 코드를 읽지 않은 상태 프로세스
- 프로세스는 죽었지만 PCB는 남아있는 상태.
좀비 프로세스 제거 방법
방법 1) 쉘에서 부모 프로세스에게 SIGCHLD 신호 보내기
(부모가 신호를 받으면 wait()호출 → 자식의 종료 상태를 읽고 PCB 제거)
방법 2) 부모 프로세스에서 강제 종료.

고아프로세스
: 부모가 먼저 종료한 자식 프로세스
| 커널 역할 | 자식(고아)를 init(#1 최상위 프로세스)에 입양시킴 |
| 쉘의 예외적 행동 | 모든 자식 프로세스를 강제 종료 하기도 함. |
| 결론 | 고아 프로세스는 결국 init이 관리하므로 좀비가 되지 않음 |

여러 종류의 프로세스 ( 간단하게만)
- 백그라운드 프로세스 : 터미널과 상호 작용하지 않고 돌아가는 작업.
- 포그라운드 프로세스 : 실행되는 동안 터미널 사용자의 입력을 독접하는 프로세스.
→ 운영체제 스케줄링 : I/O 집중 > CPU 집중
- cpu 집중 프로세스 :대부분의 시간을 계산 중심의 일을 하느라 보내는 프로세스 .
- I/O 집중 프로세스 : 입출력 작업을 하느라 대부분의 시간을 보내는 프로세스 .
Ch 3-4 프로세스 제어
1. 프로세스 생성 : fork() , CreateProcess()
: 시스템 호출을 통해서만 프로세스 생성 ⭐
<프로세스 생성 과정 > : PID → PCB → 메모리 → 준비 큐
| 1 | PID 번호 할당 | 고유한 식별자 부여 |
| 2 | PCB 생성 | 프로세스 제어 정보 저장 구조체 생성 |
| 3 | 프로세스 테이블 슬롯 확보 | 전체 목록에 새 항목 등록 |
| 4 | PCB 연결 | 프로세스 테이블과 PCB 연결 |
| 5 | 메모리 공간 확보 | 코드, 데이터, 힙, 스택 영역 준비 |
| 6 | 코드/데이터 로드 | 실행파일을 RAM에 복사 |
| 7 | PCB 정보 기록 | 상태, PC, 메모리 주소 등 설정 |
| 8 | Ready 큐 등록 | 실행 대기 상태로 스케줄러에게 전달 |
< 프로세스 생성되는 경우 5가지 >
(1) 시스템 부팅 과정에서 필요한 프로세스 생성
→ 컴퓨터가 켜질 때 자동으로 생기는 프로세스들.ex ) 커널이 로드되고 PID 1 (init 또는 systemd)가 만들어짐.
(2) 사용자 로그인 후 , 사용자와 대화를 위한 프로세스 생성
→ 사용자가 로그인 하면 나오는 프롬프트 창 (bash,zsh같은 쉘) 생성
| user login | login 프로세스 | bash 실행 |
(3) 새로운 프로세스를 생성하도록 하는 사용자 명령
→ 사용자가 쉘에 명령을 입력 했을때 쉘 내부적으로 fork() + exec()를 호출해서 새 프로세스를 만듦.
(4) 배치 작업 실행시
→예약 작업, 자동 실행 작업.
(5) 사용자 응용프로그램이 시스템 호출로 새 프로세스 생성.
→ ex ) 어떤 프로그램 안에서 직접 새 프로세스를 만드는 경우.

⚠️위에 그림에서 헷갈릴 수 있지만 pid라는 변수가 0인거지 실제 프로세스 id가 0이라는 건 아님.
Q 자식프로세스 pid는 얼마일까요?
fork()
: 현재 프로세스를 복사하여 자식 프로세스 생성.
int pid = fork();
- 부모와 동일한 모양이지만 독립된 주소 공간 소유
- fork() 리턴 값 : 부모 (자식 PID) | 자식 ( 0 )
→ 부모와 지식이 완전히 똑같은 코드를 실행하고 차이가 딱 이거 하나임.
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
pid_t pid;
int i, sum=0;
pid = fork(); // 자식프로세스 생성
if(pid > 0) { // 부모 프로세스에 의해 실행되는 코드
printf("부모프로세스: fork()의 리턴 값 = 자식프로세스 pid = %d\n", pid); //(1)⭐
printf("부모프로세스: pid = %d\n", getpid()); //(2)⭐
wait(NULL); // 자식 프로세스가 종료할 때까지 대기
printf("부모프로세스종료\n"); //(6)⭐
return 0;
}
else if(pid == 0) { // 자식 프로세스에 의해 실행되는 코드
printf("자식프로세스: fork()의 리턴 값 pid = %d\n", pid); //(3)⭐
printf("자식프로세스: pid = %d, 부모프로세스 pid = %d\n", getpid(), getppid()); // (4)⭐
for (i=1; i<=100; i++)
sum += i;
printf("자식프로세스: sum = %d\n", sum); // (5)⭐
return 0;
}
else { // fork() 오류
printf("fork 오류");
return 0;
}
}
위에 코드 실행 결과 / 순서 예상 해보기
$ gcc -o forkex forkex.c
$ ./forkex
부모프로세스: fork()의 리턴 값 = 자식프로세스 pid = 29138
부모프로세스: pid = 29137
자식프로세스: fork()의 리턴 값 pid = 0
자식프로세스: pid = 29138, 부모프로세스 pid = 29137
자식프로세스: sum = 5050
부모프로세스종료
2. 프로세스 오버레이 : exec()
: 현재 실행중인 프로세스의 주소 공간에 새로운 응용 프로그램을 적재하여 실행시키는 기법
- 새로 프로세스를 생성하는 과정은 없다.
- 프로세스의 코드, 데이터, 힙, 스택에 새로운 응용 프로그램이 적재됨.
- fork()에 의해 생성된 자식 프로세스는 생성후 바로 exec()가 실행되는 경우가 많음.
- 시스템 호출 : execlp(), execv(), execvp()
fork() → exec()
- fork() : 기존 프로세스를 복제해서 자식 프로세스 생성
- exec() : 자식 프로세스의 기존 코드 (메모리)를 새 프로그램으로 완전히 덮어쓰기



3. 자식 프로세스 종료 대기 : wait() 와 프로세스 종료 : exit()
● 프로세스 종료 (동일한 동작)
- exit() 시스템 호출
- C프로그램의 main()에서 리턴.
● 종료코드 :
= 부모 프로세스에 전달하는 값. (1~255)
=프로세스가 종료한 상태나 이유를 부모에게 전달하기 위한것.
(동일한 동작)
- main()의 리턴 값; return 종료 코드
- exit( 종료 코드 )
만약에 return -1 또는 exit(-1)을 하게 되면 0xff로 255 전달됨.
< exit() 시스템 호출로 프로세스 종료 과정 >
| 1. 자원 반환 | 프로세스의 모든 자원 해제. | 코드,데이터, 스택. 힙 등의 모든 메모리 자원을 반환. |
| 2. PCB 갱신 | 프로세스 상태 변경 및 종료 코드 저장. | terminated로 변경 → PCB에 종료 코드 저장 |
| 3. 자식 프로세스 처리 | 고아 프로세스 입양 | 부모가 먼저 종료된 경우, init() 에게 입양됨. |
| 4. 부모에게 신호 전송 | SIGCHLD 신호 발생. | 자식이 종료될때 알려줌. " 나 죽음" |
waitex.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
pid_t pid;
int status;
pid = fork(); // 자식프로세스 생성
if (pid > 0) { // 부모 프로세스 코드
printf("부모프로세스: 자식의 종료를 기다림\n");
wait(&status); // 자식프로세스 종료 대기. status에 종료 코드 받음
printf("부모프로세스: child의 종료 코드=%d\n",WEXITSTATUS(status));
return 0;
}
else if (pid == 0) { // 자식 프로세스 코드
execlp("./child", "child", NULL); // child를 자식프로세스로 실행
}
else { // fork() 오류
printf("fork 오류");
return 0;
}
}
child.c
#include <stdio.h>
int main() {
printf("I am a child\n");
return 100;
}
실행 순서 잘 생각해보기
$ gcc -o child child.c
$ gcc -o waitex waitex.c
$ ./waitex
부모프로세스: 자식의 종료를 기다림
I am a child
부모프로세스: child의 종료 코드=100
$
4. 좀비 프로세스
: 자식이 죽었는데 부모가 wait()으로 종료 코드를 읽지 않으면 커널은 PCB를 지우지 않고 남겨둠. 이 상태가 좀비 프로세스.
- 정상 종료_ main() 함수 종료나 exit() 호출
- 강제 종료 _다른 프로세스에 의해(kill)
프로세스 종료시 )
- 모든 자원이 반환되어야 함.
-PCB는 프로세스 테이블에서 제거 되지 않음. [부모 프로세스가 자식의 종료 상태를 확인 할 수 있게 남겨두는 것임]
-프로세스 상태 : terminated
⭐ 종료 코드를 읽은 뒤에서 커널에서 해당 PCB가 완전히 삭제됨.

좀비 상태는 프로세스 테이블에서 확인 가능. (S가 Z로 표기)
'[전공 CS] > [컴퓨터 구조론][운영체제]' 카테고리의 다른 글
| [운영체제] 5장 CPU 스케줄링 (0) | 2025.12.07 |
|---|---|
| [운영체제] 04 스레드와 멀티 스레드 (0) | 2025.10.21 |
| [운영체제] 02 컴퓨터 시스템과 운영체제 (0) | 2025.09.30 |
| [운영체제] 01 운영체제의 시작과 발전+ 전체 문제풀이 (0) | 2025.09.25 |
| [컴퓨터 구조론] Ch 07 시스템 버스, I/0및 인터럽트 (2) | 2025.06.12 |