[운영체제] 3. 프로세스와 프로세스 관리

황재성·2022년 5월 30일
0

운영체제

목록 보기
3/9

프로세스 개요

프로세스 개요

** 프로그램 : 하드디스크 등의 저장 매체에 저장. 실행 파일의 형태

  • 프로세스 : 프로그램이 메모리에 적재되어 실행 중인 상태
    - 필요한 모든 자원 할당 받음
    - 자원 : 코드공간, 데이터공간, 스택공간, 힙공간

프로세스 특징

  • 프로세스 특징
  1. 운영체제는 프로그램을 메모리에 적재하고 프로세스로 다룸
  2. 운영체제는 프로세스에게 실행에 필요한 메모리 할당, 이곳에 코드와 데이터 등 적재
  3. 프로세스들은 서로 독립적인 메모리 공간을 가짐. 다른 프로세스의 영역에 접근 불허
  4. 커널은 각 프로세스의 메모리 위치와 크기 정보를 관리한다.
  5. 커널은 프로세스마다 고유한 번호(프로세스 ID) 할당
  6. 프로세스에 관한 모든 정보는 커널이 관리
  7. 프로세스는 실행-대기-잠자기-대기-실행-종료 등의 생명주기를 가짐
  8. 프로세스를 만들고, 실행하고, 대기시키고, 종료시키는 모든 관리는 커널에 의해 수행

프로세스 관리

  • 프로세스의 생성에서 종료까지 관리는 모두 커널에 의해 이루어짐
    - 커널 영역에 프로세스 테이블을 만들고, 프로세스의 목록 관리

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

  • 프로그램의 다중 인스턴스
    - 한 프로그램을 여러 번 실행시켜 다중 인스턴스를 생성하면 어떻게 될까?
    - 운영체제는 프로그램을 실행할 때마다 독립된 프로세스 생성

    • 각 프로세스에게 독립된 메모리 공간 할당
    • 운영체제는 다중 인스턴스 프로세스들을 별개의 프로세스들로 취급

CPU 주소 공간

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

  • 공간 크기
    - CPU의 주소선의 수에 의해 결정
    - 32비트 CPU -> 32개의 주소선 -> 232개의 주소 -> 4GB 공간

  • 주소공간은 0번지부터 시작
    - 1번지의 저장 공간 크기는 1바이트

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

  1. 코드 영역
  • 실행될 프로그램 코드가 적재되는 영역
  • 사용자가 작성한 모든 함수의 코드
  • 사용자가 호출한 라이브러리 함수들의 코드
  1. 데이터 영역 (상수 공간)
  • 전역 변수 공간, 정적 데이터 공간 ( 사용자 프로그램과 라이브러리 포함 )
  • 프로그램에서 고정적으로 만든 변수 공간 (상수 공간)
  • 프로세스 적재 시 할당, 종료 시 소멸
  1. 힙 영역
  • 프로세스가 실행 도중 동적으로 사용할 수 있도록 할당된 공간
  • malloc() 등으로 할당받는 공간은 힙 영역에서 할당
  • 힙 영역에서 아래 번지로 내려가면서 할당
  1. 스택 영역
  • 함수가 실행될 때 사용될 데이터를 위해 할당된 공간
  • 매개변수들, 지역변수들, 함수 종료 후 돌아갈 주소 등
  • 함수는 호출될 때, 스택 영역에서 위쪽으로 공간 할당
  • 함수가 return 하면 할당된 공간 반환

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

프로세스 주소 공간

  • 프로세스가 실행 중에 접근할 수 있도록 허용된 주소의 최대 범위
  • 프로세스 주소 공간은 논리 공간(가상 공간) - 0번지에서 시작하여 연속적인 주소
  • 프로세스 주소 공간 크기
    - CPU 가 엑세스할 수 있는 전체 크기 ( 32비트 CPU의 경우, 4GB )
    - 프로세스 주소 공간 크기는 프로세스의 현재 크기와 다름
    - 프로세스 주소 공간의 크기 : 프로세스가 액세스할 수 있는 최대 크 기
    - 프로세스 현재 크기 : 적재된 코드 + 전역변수 + 힙 영역에서 할당받아 사용 중인 동적 메모리 공간 + 현재 스택 영역에 저장된 데이터 크기

** 프로세스 주소 공간은 2부분으로 나뉘어짐

1) 사용자 공간

  • 프로세스의 코드, 데이터, 힙, 스택 영역이 할당되는 공간
  • 코드와 데이터 영역의 크기는 프로세스 시작 시 결정
  • 힙과 스택 영역의 크기는 정해져 있지 않음
  • 힙 영역은 아래로 자라고, 스택은 위로 자람

2) 커널 공간

  • 프로세스가 시스템 호출을 통해 이용하는 커널 공간
  • 커널 코드, 커널 데이터, 커널 스택(커널 코드가 실행될 때)
  • 커널 공간은 모든 사용자 프로세스에 의해 공유 ( 프로세스나 스레드가 스택이나 힙을 소유 )

프로세스 주소 공간의 특징

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

  • 프로세스의 주소 공간은 사용자나 개발자가 보는 관점
    - 자신이 작성한 프로그램이 0번지부터 시작하여,
    - 연속적인 메모리 공간에 형성되고,
    - CPU가 액세스할 수 있는 최대 크기의 메모리가 설치되어 있다고 상상

  • 실제 상황
    - 설치된 물리 메모리의 크기는 주소 공간보다 작을 수 있고,
    - 프로세스의 코드, 데이터, 힙, 스택은 물리 메모리에 흩어져 저장됨 (연속적인 메모리 공간이 아님)

  1. 프로세스 주소 공간은 프로세스별로 주어지는가? YES
  • 프로세스마다 주소 공간은 별개이다.
  1. 그러면, 프로세스 주소 공간은 충돌하는가? NO
  • 프로세스 주소 공간은 가상 주소 공간이다.
  • 가상 주소가 실제 주소로 매핑되므로, 물리 메모리에서는 충돌하지 않는다.

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

  • 사용자는 연속적인 공간(가상 주소 공간)으로 생각 -> 그러나 가상 주소의 데이터가 실제 메모리에 분산되어 있어 어느 번지에 있을지 알 수 없음
  • 가상메모리 운영 방식 : LRU (least, recently, uses- 최근 최소 사용) 필요한 것만 RAM으로 가져오고 오래동안 사용하지 않는 건 하드디스크에 내려놓는다.

커널 공간의 의미

** 각 프로세스는 독립된 사용자 공간 소유, 커널 공간 공유

  • 커널 공간
    - 프로세스가 사용자 코드에서 시스템 호출을 통해 커널 코드 실행할 때 커널 공간 사용
    • 사용자 프로세스가 커널 모드에서 실행되고 있다고 함
    • 커널 코드를 실행하고 있는 것은 사용자 프로세스임
    • 커널 코드가 적재된 물리 메모리의 위치 역시 사용자 프로세스가 소유한 매핑 테이블 사용
  • 사용자 공간과 커널 공간의 결론
    - 프로세스마다 각각 사용자 주소 공간이 있다.
    - 시스템 전체에는 하나의 커널 주소 공간이 있다.
    - 모든 프로세스는 커널 주소 공간을 공유한다.

커널의 프로세스 관리

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

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

1) 프로세스 테이블

  • 시스템의 모든 프로세스들을 관리하기 위한 표
  • 시스템에 한 개만 있음
  • 구현 방식은 운영체제마다 다름

2) 프로세스 제어 블록(PCB : Process Control Block)

  • 프로세스에 관한 정보를 저장하는 구조체
  • 프로세스 당 하나씩 존재
  • 프로세스가 생성될 때 만들어지고 종료되면 삭제
  • 커널에 의해 생성, 저장, 읽혀지는 등 관리
  • nice 값 : Linux 상에서 Process 가 실행될 때, nice 라는 값을 가지고 실행되는데, nice 값은 process 간의 우선순위를 말함
  • 프로세스 제어 블록에 저장되는 정보 (운영체제마다 프로세스 제어 블록에 저장되는 요소와 프로세스 상태 등이 다름)
  1. 프로세스 번호(PID, Process ID) : 정수, 유일한 번호, 이 번호로 프로세스 구분
  2. 부모 프로세스 번호(PPID, Parent Process ID) : 부모 프로세스의 PID
  3. 프로세스 상태(Process State) 정보
  4. CPU 컨텍스트 정보
  • PC(Program Counter) : 선택되면 실행을 시작할 프로세스 내 코드 주소
    - 사용자 모드에 있었던 경우, 사용자 공간의 코드 주소
    - 커널 모드에 있었던 경우, 커널 공간의 코드 주소
    - SP(Stack Pointer)
    - 기타 레지스터
  1. 스케줄링 정보
  • 우선 순위 값, nice 값, 스케줄 큐에 대한 포인터 등
  1. 프로세스 종료 코드(정수 0 ~ 255)
  • exit() 시스템 호출의 매개변수 값, return 문의 리턴 값. 부모 프로세스에게 전달
  1. 열어놓은 파일 디스크립터들이 저장되는 배열
  2. 메모리 관리 정보
  • 페이지 테이블의 메모리 위치, 프로세스에게 할당된 물리 메모리의 주소 등
  1. 프로세스 사이의 통신 정보들
  2. 회계 정보
  • CPU의 사용 시간, 시간 제한, 프로세스의 총 경과시간 등
  1. 프로세스 소유자 이름
  • 프로세스를 생성한 사용자의 로그인 이름 정보

프로세스의 생명주기

  1. New(생성 상태)
  • 프로세스가 생성된 상태. 메모리 할당 및 필요한 자원 적재
  1. Ready(준비 상태)
  • 프로세스가 스케줄링을 기다리는 준비 상태
  • 프로세스는 준비 큐에서 대기
  • 스케줄링 되면 Running 상태로 되고 CPU에 의해 실행됨
  1. Running(실행 상태)
  • 프로세스가 CPU에 의해 현재 실행되고 있는 상태
  • CPU의 시간할당량(타임슬라이스)가 지나면 다시 Ready 상태로 바뀌고 준비 큐에 삽입
  • 프로세스가 입출력을 시행하면 커널은 프로세스를 Blocked 상태로 만들고 대기 큐에 삽입
  1. Blocked/Wait(블록 상태)
  • 프로세스가 자원을 요청하거나, 입출력을 요청하고 완료를 기다리는 상태
  • 입출력이 완료되면 프로세스는 Ready 상태로 바뀌고 준비 큐에 삽입
  1. Terminated/Zombie 상태
  • 프로세스가 종료된 상태 (프로세스가 차지하고 있던 메모리와 할당받았던 자원들을 모두 반환, 열어 놓은 파일 닫힘)
  • 프로세스가 PCB에 남긴 종료코드를 부모 프로세스가 읽어가지 않아 완전히 종료되지 않은 상태 - 좀비 상태라고 부름
  • 아직 PCB가 남아있음
  1. Terminated/Out 상태
  • 프로세스가 종료하면서 남긴 종료코드를 부모 프로세스가 읽어 가서 완전히 종료된 상태
  • 프로세스 테이블의 항목과 PCB가 시스템에서 완전히 제거된 상태

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

  • 프로세스 스케줄링
    - 과거 운영체제에서 실행단위는 프로세스였음
    - Ready 상태의 프로세스 중에 실행 시킬 프로세스 선택

  • 오늘날 운영체제는 스레드를 대상으로 스케줄링
    - 오늘날 프로세스 스케줄링은 없음
    - 오늘날 운영체제에서 실행 단위는 스레드
    - Ready 상태의 스레드 중 실행시킬 스레드 선택

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

프로세스 계층 구조

프로세스 부모-자식 관계

** 프로세스는 일반적으로 부모-자식 관계 (윈도우에서 프로세스는 모두 동등 - 계층 관계 아님)

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

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

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

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

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

fork(), clone() 등의 커널 코드가 자식 프로세스 생성
예외 : PID 0,1,2 등의 몇몇 조상 프로세스는 시스템 호출이 아닌 수작업으로 생성

리눅스 사례
#0 프로세스 - swapper/idle 프로세스 (hand-crafted)
#1 프로세스 - init 프로세스(hand-crafted)
- 부팅 후 생성되는 모든 사용자 프로세스의 조상
#2 프로세스 - kthreadd 프로세스
- 커널 모드에서 커널 코드로만 실행되는 모든 커널 프로세스의 조상

#0과 #1 프로세스 : idle 프로세스와 init 프로세스

  • #0 프로세스
    - 최고의 어른(조상) 프로세스
    - Unix의 #0 프로세스

    • swapper 라고 불림, 부팅을 담당하고 #1 프로세스 생성
  • Linux의 #0 프로세스
    - idle 프로세스, 부팅 관여 없이 아무 일도 하지 않고 루프

    • 우선 순위가 가장 낮은 프로세스, 다른 프로세스가 있으면 실행될 일 없음
    • 실행 중인 프로세스가 1개도 없는 상태에 빠지지 않게 하기 위해 만든 프로세스
    • Unix 시절의 관례에 따르기 위해 만들어진 프로세스
  • Windows의 #0 프로세스 : system idle process(시스템 유휴 프로세스)

    • 아무 일도 하지 않고 루프를 도는 단순 프로세스
  • 프로세스를 다루는 시스템 호출

  1. fork() - 자식 프로세스를 생성하는 시스템 호출
  2. exit() - 프로세스의 종료를 커널에 알리는 시스템 호출
  3. wait() - 부모가 자식 프로세스의 종료를 기다리고 확인하는 시스템 호출

프로세스 종료

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

  • 프로세스가 종료할 때
    - PCB에, 종료 코드 저장
    - PCB에 프로세스 상태를 Terminated 라고 표시
    - 프로세스에게 할당된 모든 메모리 반환

    • PCB와 프로세스 테이블의 항목은 제거되지 않음
  • 부모 프로세스의 의무
    - wait() 시스템 호출을 통해 프로세스의 종료 코드를 읽어야 함

  • 좀비 프로세스
    - 종료하였지만, 부모가 종료 코드를 읽지 않은 상태의 프로세스
    - 프로세스 리스트를 출력할 때(ps명령으로) 나타남

  • 좀비 프로세스 제거
    - 부모에게 SIGCHLD 핸들러가 없다면 좀비는 제거되지 못함
    - 부모 프로세스를 강제 종료시키면,
    - 좀비는 init 프로세스의 자식이 되고
    - init이 wait() 호출하여 좀비 프로세스 제거
    - 쉘에서 부모 프로세스에게 SIGCHLD 신호보내기

    • 부모 프로세스에서 wait() 함수를 호출하여 처리

고아 프로세스와 입양

고아 프로세스 : 부모가 먼저 종료한 자식 프로세스

  • 부모 프로세스가 종료할 때
    - 일반적으로
    • 커널(exit() 시스템 호출 코드)은 자식 프로세스가 있는지 확인
    • 커널은 자식 프로세스(고아)를 init 프로세스에게 입양

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

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

여러종류의 프로세스

1) 백그라운드 프로세스

  • 터미널에서 실행되었지만, 터미널 사용자와 대화가 없는 채 실행되는 프로세스
  • 사용자와 대화없이 실행되는 프로세스
  • 사용자 입력을 필요로 하지 않는 프로세스
  • idle 상태로 잠을 자거나 디스크에 스왑된 상태의 프로세스

2) 포그라운드 프로세스

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

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

  • CPU 집중프로세스
    - 대부분의 시간을 계산 중심의 일(CPU 작업)을 하느라 보내는 프로 세스
    - 배열 곱, 인공지능 연산, 이미지 처리
    - CPU 속도가 성능 좌우

  • I/O 집중 프로세스
    - 입출력 작업을 하느라 대부분의 시간을 보내는 프로세스
    - 네트워크 전송, 파일 입출력에 집중된 프로세스
    - 파일 서버, 웹 서버
    - 입출력 장치나 입출력 시스템의 속도가 성능 좌우

  • 운영체제의 스케줄링 우선순위 : I/O 집중 프로세스 > CPU 집중 프로세스
    - I/O 작업을 하는 동안 다른 프로세스에게 CPU 할당 가능

프로세스 제어

프로세스 생성

  • 컴퓨터 시스템에서 프로세스가 생성되는 5가지 경우
    - 시스템 부팅과정에서 필요한 프로세스 생성
    - 사용자의 로그인 후 사용자와 대화를 위한 프로세스 생성(bash 등 쉘)
    - 새로운 프로세스를 생성하도록 하는 사용자의 명령(vi a.c, vi hello.c)
    - 배치 작업 실행 시(at, batch 명령, "몇 시에 ~해라")
    - 사용자 응용프로그램이 시스템 호출로 새 프로세스 생성

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

  • 시스템 호출을 통해서만 프로세스 생성
    - 커널만이 프로세스 생성가능
    - 리눅스 : fork() 시스템 호출
    - windows : CreateProcess() 등 시스템 호출

  • 프로세스 생성 과정
    1) 새로운 PID 번호 할당
    2) PCB 구조체 생성
    3) 프로세스 테이블에서 새 항목 할당
    4) 새로운 프로세스를 위한 메모리 공간 할당
    -> 프로세스의 코드, 데이터, 스택, 힙 영역
    -> 할당받은 메모리 공간에 프로세스의 코드와 데이터 적재
    5) PCB에 프로세스 정보 기록
    6) PCB에 프로세스 상태를 ready 상태로 표시하고, 준비 큐에 넣어서 차후 스케줄되게 함

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

int pid = fork();
-> 자식 프로세스 생성
-> 부모 프로세스의 모든 환경, 메모리, PCB 등을 복사
-> 부모와 동일한 모양이지만, 독립된 주소 공간 소유

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

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

프로세스 오버레이(process overlay)

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

exec 패밀리 시스템 호출
-> execlp(), execv(), execvp() 시스텔 호출들
-> 실행 파일을 로딩하여 현재 프로세스의 이미지 위에 단순히 덮어쓰고 새로운 프로세스의 생성 과정을 거치지 않는다.

프로세스의 PID 변경 없음

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

보통 fork() 를 통해 생성된 자식 프로세스가 exec() 실행

프로세스 종료와 종료 대기

  • 프로세스 종료
    - exit() 시스템 호출
    - C프로그램의 main() 에서 리턴

    • exit() 시스템 호출이 결국 실행되도록 컴파일 됨
  • 종료 코드
    - 부모 프로세스에게 전달하는 값

    • main() 함수의 리턴 값; return 종료 코드;
    • exit(종료코드)
  • exit() 시스템 호출로 프로세스 종료 과정

1) 프로세스의 모든 자원 반환
- 코드, 데이터, 스택, 힙 등의 모든 메모리 자원을 반환
- 열어 놓은 파일이나 소켓 등을 닫음

2) PCB에 프로세스 상태를 Terminated 로 변경, PCB 에 종료 코드 저장
3) 자식 프로세스들을 init 프로세스에게 입양
4) 부모 프로세스에게 SIGCHLD 신호 전송
- 부모가 SIGCHLD 신호 처리기를 작성하여 wait() 시스템 호출로 자식의 종료 코드 읽기 실행
- 혹은 언젠가 부모가 자식의 죽음 처리. 그동안 자식은 좀비 상태에 있음

종료코드의 의미와 범위

1) 종료 코드

  • 프로세스가 종료한 상태나 이유를 부모에게 전달하기 위한 것
  • POSIX 표준에서 0 ~ 255 사이의 1바이트 숫자
    - 정상종료는 0
    - 1~255 : 개발자가 종료 이유를 임의로 정해 사용

2) 종료 코드 사용 시 유의할 점

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

int main(){
return 300; // return 44; 와 같음
}
void func(){
exit(300); // exit(44) 와 같음
}

  • -1을 리턴하는 경우 (return -1, 혹은 exit(-1))
    -> -1 -> 0xff -> 양의 정수로 255. 그러므로 종료 코드로 255가 전달

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

1) 프로세스 종료

  • 두 종류
    - C언어에서 main() 함수의 종료나 exit() 을 호출한 정상 종료
    - 다른 프로세스에 의해 강제 종료

2) 프로세스가 종료되면

  • 차지하고 있던 메모리와 자원 모두 반환
  • PCB는 프로세스 테이블에서 제거되지 않음
  • 프로세스 상태 : Terminated

** 죽은 프로세스가 wait(), 혹은 CloseHandle() 시스템 호출을 통해, 죽은 자식이 남긴 정보를 읽게 되면 자식 프로세스의 PCB 가 완전히 제거

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

이 글이 문제가 된다면 삭제하겠습니다.

profile
데이터사이언스와 자연어처리를 공부하고 있습니다.

0개의 댓글