코딩 기록 저장소

[23-01/운영체제] 프로세스와 프로세스 관리 본문

학교 공부/운영체제

[23-01/운영체제] 프로세스와 프로세스 관리

KimNang 2023. 4. 21. 20:44

1. 프로세스 개요

프로세스 개요

■ 프로그램 (Program)

- 하드디스크 등의 저장 매체에 저장. 실행 파일의 형태

■ 프로세스 (Process)

- 프로그램이 메모리에 적재되어 실행 중인 상태

    - 필요한 모든 자원 할당 받음

    - 자원 : 코드 공간, 데이터 공간, 스택 공간, 힙 공간 - 메모리

● 프로세스의 특징

- 운영체제는 프로그램을 메모리에 적재하고 프로세스로 다룸

- 운영체제는 프로세스에게 실행에 필요한 메모리 할당, 이곳에 코드와 데이터 등 적재

- 프로세스들은 서로 독립적인 메모리 공간을 가짐. 다른 프로세스의 영역에 접근 불허

- 운영체제는 각 프로세스의 메모리 위치와 크기 정보를 관리함.

- 운영체제는 프로세스마다 고유한 번호 (프로세스 ID) 할당

- 프로세스의 관한 모든 정보는 커널에 의해 관리

- 프로세스는 실행 - 대기 - 잠자기 - 대기 - 실행 - 종료 등의 생명 주기를 가짐

- 프로세스 생성, 실행, 대기, 종료 등의 모든 관리는 커널에 의해 수행 ★

 

프로그램과 프로세스

- 프로세스들은 상호 독립적인 메모리 공간에서 실행

 

프로세스 관리

- 프로세스의 생성에서 종료까지, 관리는 모두 커널에 의해 이루어짐

    - 커널 영역에 프로세스 테이블을 만들고, 프로세스들 목록 관리

- 관리 내용

    - 프로세스 생성, 실행, 일시 중단 및 재개, 정보 관리, 프로세스 통신, 프로세스 동기화, 프로세스 중단, 프로세스 컨텍스트 스위칭

프로그램의 다중 인스턴스

■ 한 프로그램을 여러 번 실행시키면 어떻게 될까?

- 프로그램 실행 시 마다 독립된 프로세스 생성 -> 프로세스들을 프로그램의 다중 인스턴스라고 부름

- 각 프로세스에게 독립된 메모리 공간 할당

- 각 프로세스를 별개의 프로세스로 취급

 

CPU 주소 공간

■ CPU 주소 공간 (CPU address space)

- CPU가 주소선을 통해 액세스할 수 있는 전체 메모리 공간

- 공간 크기

    - CPU 주소선의 수에 의해 결정

- 32비트 CPU -> 32개의 주소선 -> 2³²개의 주소 -> 2³² 바이트 -> 4GB 공간

    - 1번지의 저장 공간 크기는 1바이트

    - 주소 공간은 0번지부터 시작 ~

- CPU 주소 공간보다 큰 메모리? 있어도 액세스 불가능

- CPU 주소 공간보다 작은 양의 메모리? 가능

    - CPU가 설치된 메모리의 주소 영역을 넘어 액세스하면 시스템 오류

ex) 32비트 CPU를 가진 컴퓨터 (4GB까지 메모리 액세스 가능)에 2GB의 메모리가 설치되어 있을 때 2GB를 넘어서 액세스하면 없는 메모리를 액세스하므로 심각한 오류 발생

 

프로세스 구성 - 4개의 메모리 영역

1. 코드 (code) 영역

- 실행될 프로그램 코드가 적재되는 영역

    - 사용자가 작성한 모든 함수의 코드

    - 사용자가 호출한 라이브러리 함수들의 코드

 

2. 데이터 (data) 영역

- 프로그램에서 고정적으로 만든 변수 공간

    - 전역 변수 공간, 정적 데이터 공간

    - 사용자 프로그램과 라이브러리 포함

- 프로세스 적재 시 할당, 종료 시 소멸

 

3. 힙 (heap) 영역  생성자

- 프로세스의 실행 도중 동적으로 사용할 수 있도록 할당된 공간

    - malloc() 등으로 할당받는 공간은 힙 영역에서 할당

    - 힙 영역에서 아래 번지로 내려가면서 할당

4. 스택 (stack) 영역

- 함수가 실행될 때 사용될 데이터를 위해 할당된 공간

    - 매개변수들, 지역 변수들, 함수 종료 후 돌아갈 주소 등

    - 함수는 호출될 때, 스택 영역에서 위쪽으로 공간 할당

    - 함수가 return 하면 할당된 공간 반환

- 함수 호출 외에 프로세스에서 필요시 사용 가능

 

memo: 이론적으로 중요함. 코드 짤 땐 신경 안써도 됨.

 

프로세스 주소 공간

■ 프로세스 주소 공간

- 프로세스가 실행 중에 접근할 수 있도록 허용된 주소의 최대 범위

- 프로세스 주소 공간은 논리 공간 (가상 공간)  가상 공간 ≠ 가상 메모리

    - 0번지에서 시작하여 연속적인 주소

 

■ 프로세스 주소 공간의 크기

● CPU가 액세스할 수 있는 전체 크기

- 32비트 CPU의 경우 4GB (윈도우, 리눅스 모두 동일)

- 프로세스 주소 공간 크기는 프로세스의 현재 크기와 다름

 

● 프로세스 주소 공간의 크기

- 프로세스가 액세스할 수 있는 최대 크기 (32비트 CPU 경우 4GB)

 

● 프로세스의 크기

- 적재된 코드 +

- 전역 변수 +

- 힙 영역에서 현재 할당받은 동적 메모리 공간 +

- 스택 영역에 현재 저장된 데이터 크기

 

프로세스의 사용자 공간과 커널 공간

■ 프로세스 주소 공간 = 사용자 공간 + 커널 공간 (가상 공간)

● 사용자 공간

- 프로세스의 코드, 데이터, 힙, 스택 영역이 순서대로 할당되는 공간

- 코드와 데이터 영역의 크기는 프로세스 적재 시 결정

- 힙은 데이터 영역 바로 다음부터 시작하고,

- 스택은 사용자 공간의 바닥에서 시작하여 거꾸로 자람

- 힙 영역은 높은 번지로 자라고, 스택은 낮은 번지로 자람

    - ex) 처음 malloc(1000)으로 동적 할당받는 공간은 데이터 영역 바로 다음의 힙 시작부분부터 할당

    - ex) 처음 함수가 호출될 때 할당되는 스택 공간은 스택 영역 바닥부터 위로 할당

 

● 커널 공간

- 프로세스가 시스템 호출을 통해 이용하는 커널 공간

- 커널 코드, 커널 데이터, 커널 스택 (커널 코드가 실행될 때)이 존재

 

■ 결론

- 프로세스의 코드와 데이터는 실행 파일에 결정된 상태로 코드 영역과 데이터 영역에 적재 -> 실행 중에 크기가 변하지 않음

- 프로세스는 사용자 공간의 최대 범위까지 동적할당 받으면서 힙 영역스택 영역을 늘려갈 수 있음

(스택 영역: 복귀 주소)

 

■ 프로세스 주소 공간 사례

 

커널 공간의 의미

■ 각 프로세스

- 독립된 사용자 공간 소유

- 커널 공간 소유

 

■ 커널 공간

- 프로세스가 사용자 코드에서 시스템 호출을 통해 커널 코드 실행할 때 커널 공간 사용

    - 커널 코드를 실행하고 있는 것은 사용자 프로세스

    - 커널 코드가 적재된 물리 메모리의 위치 역시 사용자 프로세스가 소유한 매핑 테이블 사용

 

■ 사용자 공간과 커널 공간의 결론

- 프로세스마다 각각 사용자 주소 공간이 있음

- 시스템 전체에는 하나의 커널 주소 공간이 있음

- 모든 프로세스는 커널 주소 공간을 공유함

 

프로세스의 주소 공간은 가상 주소 공간

■ 프로세스의 주소 공간은 가상 공간

● 프로세스가 사용하는 주소는 가상 주소

- 프로세스에서 0번지는 가상 주소 0번지

- 가상 주소는 0번지부터 시작

- 프로세스 내의 코드 주소, 전역 변수에 대한 주소, malloc()에 의해 리턴된 주소, 스택에 담긴 지역 변수의 주소는 모두 가상 주소

 

● 프로세스의 주소 공간(가상 주소 공간)은 사용자나 개발자가 보는 관점

- 사용자나 개발자는 프로그램이 0번지부터 시작,

- 연속적인 메모리 공간에 형성,

- 최대 크기의 메모리가 설치되어 있다고 상상

 

● 실제 상황

- 설치된 물리 메모리의 크기는 주소 공간보다 작을 수 있음

- 프로세스의 코드, 데이터, 힙, 스택은 물리 메모리에 흩어져 저장됨 (연속적인 메모리 공간이 아님)

 

● 프로세스 주소 공간은 각 프로세스마다 주어지는가? Yes

- 프로세스마다 주소 공간은 별개

 

● 프로세스 주소 공간은 충돌하는가? No

- 프로세스 주소 공간은 가상 주소 공간

- 가상 주소가 물리 주소로 매핑되므로, 물리 메모리에서는 충돌하지 않음

 

■ 가상 주소 공간의 물리 메모리로의 매핑

- 사용자는 연속적인 공간(가상 주소 공간)으로 생각 -> 그러나 가상 주소의 데이터가 물리 메모리에 분산되어 있어 어느 물리 번지에 있을지 알 수 없음

가상 주소 공간의 물리 메모리로의 매핑

■ 프로세스들의 가상 주소 공간과 물리 메모리

- 서로 다른 공간 차지하므로 충돌 일어나지 않음

여러 프로세스들이 커널 공간 공유

2. 커널의 프로세스 관리

프로세스 테이블과 프로세스 제어 블록

■ 프로세스 테이블 (Process Table)

- 시스템의 모든 프로세스들을 관리하기 위한 표

- 시스템에 한 개만 있음

- 구현방식은 운영체제마다 다름

 

■ 프로세스 제어 블록 (Process Control Block, PCB)

- 프로세스에 관한 정보를 저장하는 구조체

- 프로세스당 하나씩 존재

- 프로세스가 생성될 때 만들어지고 종료되면 삭제

- 커널에 의해 생성, 저장, 읽혀지는 등 관리 ★

 

■ 프로세스 테이블과 프로세스 제어 블록 (PCB)

● 위치

- 커널 영역, 커널 코드(커널 모드)만이 액세스 가능

 

프로세스 제어 블록(PCB)에 저장되는 정보

1. 프로세스 번호 (PID, Process ID) : 0과 양의 정수, 유일한 번호, 이 번호로 프로세스 구분

2. 부모 프로세스 번호 (PPID, Parent Process ID) : 부모 프로세스의 PID

3. 프로세스 상태 (Process State) 정보 : 준비, 실행 중, 블록(입출력 완료대기) 등

4. CPU 컨텍스트 정보

- PC (Program Counter) : 프로세스가 선택되면 실행을 시작할 프로세스 내 코드 주소

    - 사용자 모드에 있었던 경우, 사용자 공간의 코드 주소

    - 커널 모드에 있었던 경우, 커널 공간의 코드 주소

- SP (Stack Pointer)

- 기타 레지스터

5. 스케줄링 정보

- 우선 순위 값, nice 값, 스케줄 큐에 대한 포인터 등

6. 프로세스 종료 코드 (정수 0~255)

- 프로세스가 종료할 때 남기는 정수 값. exit() 시스템 호출의 매개변수 값. main() 함수의 return 리턴 값. 부모 프로세스에게 전달

7. 프로세스의 오픈 파일 테이블 : 열어놓은 파일 디스크립터들이 저장되는 배열

8. 메모리 관리 정보

- 페이지 테이블의 물리 메모리 주소 등

9. 프로세스 사이의 통신 정보들

10. 회계 정보

- CPU의 사용 시간, 제한 시간, 프로세스의 총 경과시간 등, 사용료 계산이나 성능 통계에 사용

11. 프로세스 소유자 정보

- 프로세스를 생성한 사용자의 로그인 이름이나 사용자 ID등

* 운영체제마다 프로세스 제어 블록에 저장되는 요소와 프로세스 상태 등이 다름

 

프로세스 생명 주기와 상태 변이 (State Change)

■ 프로세스의 생명 주기

- 프로세스는 탄생에서 종료까지 여러 상태로 바뀌면서 실행

- 상태 정보는 PCB에 기록되고, 상태가 바뀔 때마다 갱신됨

 

프로세스의 상태

■ New (생성 상태)

- 프로세스가 생성된 상태. 메모리 할당 및 필요한 자원이 적재된 상태

- PCB에 New 상태로 등록. 실행 준비를 마치면 Ready 상태로 바뀜

 

■ Ready (준비 상태)

- 프로세스가 스케줄링을 기다리는 '준비 상태'

- 프로세스는 준비 큐에서 대기

- 스케줄링되면 Running 상태로 되고 CPU에 의해 실행됨

 

Running (실행 상태)

- 프로세스가 CPU에 의해 현재 실행되고 있는 상태

- CPU의 시간할당량(타임슬라이스)이 지나면 다시 Ready 상태로 바뀌고 준비 큐에 삽입

- 프로세스가 입출력을 시행하면 커널은 프로세스를 Blocked 상태로 만들고 대기 큐에 삽입

 

■ Blocked / Wait (블록 상태)

- 프로세스가 자원을 요청하거나, 입출력을 요청하고(ex: read() 시스템 호출) 완료를 기다리는 상태

- 입출력이 완료되면 프로세스는 Ready 상태로 바뀌고 준비 큐에 삽입

 

■ Terminated / Zombie 상태

- 프로세스가 불완전 종료된 상태 (좀비 상태)

    - 프로세스가 차지하고 있던 메모리와 할당받았던 자원들을 모두 커널에 의해 반환됨. 커널에 의해 열어 놓은 파일도 닫힘

    - 하지만, 프로세스 테이블의 항목과 PCB가 여전히 시스템에서 제거되지 않은 상태

    - 프로세스가 남긴 종료 코드 (PCB에 있음)를 부모 프로세스가 읽어가지 않아 완전히 종료되지 않은 상태 - 좀비 상태라고 부름

 

■ Terminated / Out 상태

- 프로세스가 종료하면서 남긴 종료 코드(PCB에 있음)를 부모 프로세스가 읽어 가서 완전히 종료된 상태

- 프로세스 테이블의 항목과 PCB가 시스템에서 완전히 제거된 상태

 

프로세스 스케줄링과 컨텍스트 스위칭

프로세스 스케줄링과 스레드 스케줄링

프로세스 스케줄링

- 과거 운영체제에서 실행 단위는 프로세스 였음

- Ready 상태의 프로세스 중에 실행 시킬 프로세스 선택

 

● 오늘날 운영체제는 스레드를 대상으로 스케줄링

- 오늘날 프로세스 스케줄링은 없음

- 오늘날 운영체제에서 실행 단위는 스레드

- Ready 상태의 스레드 중 실행시킬 스레드 선택

 

■ 프로세스의 역할

- 프로세스는 스레드들에게 공유 자원을 제공하는 컨테이너로 역할이 바뀌었음

3. 프로세스의 계층 구조

프로세스의 부모-자식 관계

■ 프로세스는일반적으로부모-자식 관계

    - 윈도우에서 프로세스는 모두 동등 - 계층 관계 아님

- #0 프로세스가시스템부팅 시 실행되는최초의프로세스, 조상프로세스

- 부모 프로세스는여러 개의 자식 프로세스를가질 수 있음

- 모든 프로세스는부모 프로세스를가짐(#0 프로세스제외)

 

■ 자식 프로세스의생성

- 모든 프로세스는프로세스(부모 )에 의해생성

- 프로세스 생성은 시스템 호출을 통해서만 가능

    - fork(), clone() 등의 커널 코드가 자식 프로세스 생성

    - 예외 : PID 0, 1, 2 등의 몇몇 조상 프로세스는 시스템 호출이 아닌 수작업(hand-craft)으로 생성

 

■ 리눅스사례

- #0 프로세스– swapper/idle 프로세스(hand-crafted)

- #1 프로세스– init 프로세스(hand-crafted)

    - 부팅 후 생성되는 모든 사용자 프로세스의 조상

- #2 프로세스– kthreadd 프로세스(hand-crafted)

    - 커널 모드에서 커널 코드로만 실행되는 모든 커널 프로세스(thread)의 조상

 

프로세스를 다루는 시스템 호출

memo : 시스템 콜 함수

■ fork()

- 자식 프로세스를 생성하는 시스템 호출

 

■ exit()

- 현재 프로세스의 종료를 커널에 알리는 시스템 호출

- 현재 프로세스의 종료를 처리하는 커널 코드 실행

 

■ wait()

- 부모가 자식 프로세스의 종료를 기다리고 확인하는 시스템 호출

 

부모 프로세스와 자식 프로세스의 실행 관계

 

좀비 프로세스 - 종료 후 방치된 자식 프로세스

■ 프로세스가 종료할 때

- PCB에 종료코드 (Exit Status) 저장

- PCB에 프로세스 상태를 Terminated라고 표시

- 프로세스에게 할당된 모든 메모리 반환

    - PCB와 프로세스 테이블의 항목은 제거되지 않음

 

■ 부모 프로세스의 의무

- wait() 시스템 호출을 통해 자식 프로세스의 종료 코드를 읽어야함

- 자식이 종료되면 부모에게 SIGCHLD 신호가 전송됨. 부모가 이 신호를 받았을 때 wait() 시스템 호출을 하도록 작성되어 있지 않다면 자식 프로세스는 계속 좀비 상태로 남아 있음

 

■ 좀비 프로세스 (Zombie Process)

- 종료했지만, 부모가 종료코드를 읽지 않은 상태의 프로세스

- 프로세스 테이블에는 아직 남아 있으므로, 프로세스 목록을 출력할 때(ps 명령으로) 나타남

 

● 좀비 프로세스 제거 방법

방법 1. 쉘에서 부모 프로세스에게 SIGCHLD 신호 보내기

- $ kill -SIGCHLD 부모프로세스의 PID'

- 부모 프로세스의 SIGCHLD 핸들러가 wait() 호출하여 좀비 자식 제거

- 부모의 SIGCHLD 핸들러가 wait() 호출하지 않으면 좀비는 제거되지 못함

 

방법 2. 부모 프로세스 강제 종료 (일반적으로 많이 사용함)

- $ kill -9 부모프로세스의 PID'

- 좀비는 init 프로세스의 자식이 되고,

- init이 wait() 호출하여 좀비 프로세스 제거

 

부모 프로세스에서 자식의 종료를 확인하는 wait() 시스템 호출

 

고아 프로세스와 입양

■ 고아 프로세스 (Orphan Process)

- 부모가 먼저 종료한 자식 프로세스

 

■ 부모 프로세스가 종료할 때

● 일반적으로

- 커널 (exit() 시스템 호출 코드)은 자식 프로세스가 있는지 확인

- 커널은 자식 프로세스(고아)를 init 프로세스에게 입양

● 운영체제에 따라, 혹은 쉘의 경우

- 모든 자식 프로세스 강제 종료시키기도 함

 

■ #0 init 프로세스에 입양되는 과정

 

여러 종류의 프로세스

■ 백그라운드 프로세스와 포그라운드 프로세스

● 백그라운드 프로세스

- 터미널에서 실행되었지만, 터미널 사용자와의 대화가 없는 채 실행되는 프로세스

- 사용자와 대화없이 실행되는 프로세스

- 사용자 입력을 필요로 하지 않는 프로세스

- idle 상태로 잠을 자거나 디스크에 스왑된 상태의 프로세스

 

● 포그라운드 프로세스

- 실행되는 동안 터미널 사용자의 입력을 독점하는 프로세스

 

■ CPU 집중 프로세스 vs. I/O 집중 프로세스

CPU 집중 프로세스 (CPU intensive process)

- 대부분의 시간을 계산 중심의 일(CPU 작업)을 하느라 보내는 프로세스

- 배열 곱, 인공지능 연산, 이미지 처리 등의 작업

- CPU 속도가 성능 좌우 (CPU bound)

 

● I/O 집중 프로세스 (I/O intensive process)

- 입출력 작업을 하느라 대부분의 시간을 보내는 프로세스

- 네트워크 전송, 파일 입출력에 집중된 프로세스

- 파일 서버, 웹 서버

- 입출력 장치나 입출력 시스템의 속도가 성능 좌우 (I/O bound)

 

-> 운영체제의 스케줄링 우선순위 : I/O 집중 프로세스 > CPU 집중 프로세스

- I/O 작업하는 동안 다른 프로세스에게 CPU 할당 가능

 

4. 프로세스 제어 (fork, exec, wait, exit)

프로세스 생성

■ 컴퓨터 시스템에서 프로세스가 생성되는 5가지 경우

  1.  시스템 부팅과정에서 필요한 프로세스
  2.  사용자의 로그인 후 사용자와 대화를 위한 프로세스 생성 (bash등 쉘)
  3.  새로운 프로세스를 생성하도록 하는 사용자의 명령 (vi a.c)
  4.  배치 작업 실행 시 (at, batch 명령)
  5.  사용자 응용프로그램이 시스템 호출로 새 프로세스 생성

 

■ 프로세스 생성

- 프로세스가 프로세스를 생성

- 시스템 호출을 통해서만 프로세스 생성

    - 커널 만이 프로세스를 생성하는 작업 가능

    - 리눅스 : fort() 시스템 호출

    - Windows : CreateProcess() 등 시스템 호출

 

프로세스 생성 과정

■ 프로세스의 생성 과정

- 새로운 PID 번호 할당

- PCB 구조체 생성

- 프로세스 테이블에서 새 항목 할당

- 새로 할당된 프로세스 테이블 항목에 PCB 연결

- 새로운 프로세스를 위한 메모리 공간 할당

    - 프로세스의 코드, 데이터, 스택, 힙 영역

    - 할당받은 메모리 공간에 프로세스의 코드와 데이터 적재

- PCB에 프로세스 정보 기록

- PCB에 프로세스 상태를 Ready로 표시하고, 준비 큐에 넣어서 차후 스케줄되게 함

 

fork() 시스템 호출로 자식 프로세스 생성

■ fork() 시스템 호출

- 현재 프로세스를 복사하여 자식 프로세스 생성

 

● int pid = fork();

- 자식 프로세스 생성

- 부모 프로세스의 모든 환경, 메모리, PCB 등을 복사

- 부모와 동일한 모양이지만, 독립된 주소 공간 소유

 

리턴 값

- 부모 프로세스에게는 자식 프로세스의 PID 리턴

- 자식 프로세스에게는 0 리턴

 

 

■ fork()의 실행 과정

프로세스 오버레이, exec()

■ 프로세스 오버레이 (Process Overlay)

- 현재 실행중인 프로세스의 주소 공간에 새로운 응용프로그램을 적재하여 실행시키는 기법

- exec 패밀리 시스템 호출

    - execlp(), execv(), execvp() 시스템 호출들

    - 실행 파일을 적재하여 현재 프로세스의 메모리 공간에 단순히 덮어쓰고, 새로운 프로세스의 생성 과정을 거치지 않음.

- 프로세스의 PID 변경 없음

- 프로세스의 코드, 데이터, 힙, 스택에 새로운 응용프로그램이 적재됨

- fork()에 의해 생성된 자식 프로세스는 생성 후 바로 exec()을 실행하는 경우가 다반사임

 

■ exec()을 이용해 /bin/ls 응용프로그램을 실행시키는 사례

 

프로세스 종료와 프로세스 종료 대기

■ 프로세스 종료

- exit() 시스템 호출

- C 프로그램의 main()에서 리턴

    - exit() 시스템 호출이 진행됨

 

■ 종료 코드

- 부모 프로세스에게 전달하는 값

    - main() 함수의 리턴 값; return 종료코드;

    - exit(종료코드)

 

■ exit() 시스템 호출로 프로세스 종료 과정

1. 프로세스의 모든 자원 반환

- 코드, 데이터, 스택, 힙 등의 모든 메모리 자원을 반환

- 열어놓은 파일이나 소켓 등 닫음

2. PCB에 프로세스 상태를 Terminate로 변경, PCB에 종료 코드 저장

3. 자식 프로세스들이 있으면 이들을 init 프로세스에게 입양

4. 부모 프로세스에게 SIGCHLD 신호 전송

- 부모가 SIGCHLD 신호 핸들러를 작성하고 여기서 wait() 시스템 호출을 이용해 자식의 종료 코드 읽기 실행

- 혹은 언젠가 부모가 자식의 죽음 처리. 그동안 자식은 좀비 상태에 있음

 

종료 코드의 범위와 의미

■ 종료 코드 (Exit Code)

- 프로세스가 종료한 상태나 이유를 부모에게 전달하기 위한 것

- POSIX 표준에서 0~255사이의 1바이트 숫자

    - 정상 종료는 0

    - 1~255 - 개발자가 종료 이유를 임의로 정해 사용

 

■ 종료 코드 사용 시 유의할 점

- main이나 exit()에서 255 이상의 값을 사용할 때 유의

 

- -1을 리턴하는 경우 (return -1, 혹은 exit(-1))

    - -1 -> 0xff -> 양의 정수로 255. 그러므로 종료 코드로 255가 전달됨

 

프로세스 종료와 좀비 프로세스

■ 프로세스 종료

● 두 종류

  1. C언어에서 main() 함수의 종료나 exit()을 호출한 정상 종료
  2. 다른 프로세스에 의해 강제 종료(kill)

● 프로세스가 종료되면

- 차지하고 있던 메모리와 자원 모두 반환

- PCB는 프로세스 테이블에서 제거되지 않음

- 프로세스 상태 : Terminated

 

- 부모 프로세스가 wait() 시스템 호출을 통해 죽은 자식이 남긴 종료 코드를 읽게 되면 자식 프로세스의 PCB가 제거

 

■ 좀비 프로세스

- 종료할 때 리턴한 정보(main() 함수에서 리턴값, 종료 코드)를 부모 프로세스가 읽지 않았을 때, 죽었지만 PCB만 남아 완전히 제거되지 못한 상태