프로세스

실행중인 프로그램

  • 보조기억장치에 저장된 프로그램을 실행해서 메모리에 적재하고 실행되는 순간에 프로그램은 프로세스가 됨

 

 

  • 프로세스는 작업관리자에서도 쉽게 확인할 수 있음

 

 

PS 명령어

  • 리눅스, macOS
  • 프로세를 확인하는 명령어

 

 

 

 

 

 

 

프로세스의 종류


포그라운드 프로세스(foreground process)

  • 사용자가 볼 수 있는 공간에서 실행되는 프로세스

 

백그라운드 프로세스(background process)

  • 사용자가 볼 수 없는 공간에서 실행되는 프로세스 
  • 2가지 종류로 나뉨
    • 사용자와 직접 상호작용이 가능한 백그라운 프로세스
    • 사용자와 상호작용하지 않고 그저 정해진 일만 수행하는 프로세스 
      = 데몬(daemon) or 서비스(service)

작업관리자에서 서비스 확인

 

 

 

 

 

프로세스 제어 블록(PCB)


  • 모든 프로세스는 자원 실행을 위해 CPU가 필요하지만, CPU자원은 한정되어 있다
  • 그래서 프로세스들은 돌아가며 한정된 시간 만큼만 CPU를 이용한다
    • 자신의 차례에 정해진 시간 만큼 CPU 이용
    • 타이머 인터럽트가 발생하면 차례 양보

  • 빠르게 번갈아 수행되는 프로세스들을 관리해야 하는데,
    이를 위해 사용하는 자료구조가 프로세스 제어 블록(PCB)

 

프로세스 제어 블록

  • 프로세스 관련 정보를 저장하는 자료 구조
  • 마치 상품에 달린 태그와 같은 정보
  • 프로세스 생성 시 커널 영역에 생성, 종료 시 폐기
  • PCB에 담기는 정보는 운영체제마다 차이가 있음

 

PCB에 담기는 대표적인 정보

  • 프로세스 ID (= PID)
  • 레지스터 값
  • 프로세스 상태
  • CPU 스케줄링 정보
  • 메모리 정보
  • 사용한 파일과 입출력장치 정보 

 

 

 

PCB에 담기는 정보 자세히 보기

  • 프로세스 ID (= PID)
    • 특정 프로세스를 식별하기 위해 부여하는 고유한 번호(학교의 사번, 회사의 사번)
      작업관리자 - 상태 위 우클릭 - PID
  • 레지스터 값
    • 프로세스는 자신의 실행 차례가 오면 이전까지 사용한 레지스터 중간 값을 모두 복원 => 실행 재개
    • 프로그램 카운터, 스택 카운터.. 등의 레지스터 값을 저장
  • 프로세스 상태
    • 생성 / 대기 / 준비 / 실행 / 종료 상태 등(아래에서 자세히)
  • CPU 스케줄링 정보
    • 프로세스마다 CPU를 돌아가면서 사용하지만, 동일한 시간만큼 사용하는 것은 아님
    • 그러므로 언제 어떤 순서로 CPU를 할당받아 사용할지에 대한 스케줄링 정보를 저장해 둠
  • 메모리 정보
    • 프로세스가 어느 주소에 저장되어 있는지에 대한 정보
    • 페이지 테이블 정보(메모리 주소를 알 수 있는 정보)
  • 사용한 파일과 입출력장치 정보 
    • 할당된 입출력장치, 사용 중인(열린) 파일 정보 

 

 


문맥 교환 (context switch)


  • 기존의 실행 중인 프로세스의 문맥을 백업하고
    새로운 프로세스 실행을 위해 문맥을 복구하는 과정(context switching)
  • 여러 프로세스가 끊임없이 빠르게 번갈아가며 실행되는 원리

  • 한 프로세스(A)에서 다른 프로세스(B)로 실행 순서가 바뀌는 과정
    1. 기존에 실행되던 프로세스 A는 지금까지 중간 정보를 백업
      • 프로그램 카운터 등 각종 레지스터 값, 메모리 정보, 열었던 파일, 사용한 입출력 장치 등 다음 차례가 왔을 때 실행을 재개하기 위한 정보
      • 이러한 정보를 문맥(context) 라고 함
      • 실행 문맥을 백업해두면 언제든 해당 프로세스의 실행을 재개할 수 있음
    2. 뒤이어 실행할 프로세스 B의 문맥을 복구
      • 자연스럽게 실행 중인 프로세스가 바뀜 

 

 


프로세스의 메모리 영역


  • 커널 영역에는 PCB가, 사용자 영역에는?
  • 대표적으로 4가지 영역 : 코드 영역(= 텍스트 영역), 데이터 영역, 힙 영역, 스택 영역 

 

 

정적 할당 영역

  • 코드영역과 데이터 영역
  • 크기가 변하지 않음 

 

코드 영역 ( = 텍스트 영역)

  • 실행할 수 있는 코드, 기계어로 이루어진 명령어 저장
  • 데이터가 아닌 CPU가 실행할 명령어가 담기기 때문에, 쓰기가 금지된 영역(read-only)
    (프로그램은 데이터와 명령어로 이루어져 있음. 프로그램을 구성하는 명령어, 실제로 프로그램이 순차적으로 실행해야 하는 명령어가 저장되는 공간이기에 갑자기 바뀔 일은 없음)

데이터 영역

  • 잠깐 썼다가 없앨 데이터가 아닌 프로그램이 실행되는 동안 유지할 데이터 저장
  • ex) 전역변수 

 

 

동적 할당 영역

  • 스택 영역과 힙 영역
  • 동적으로 크기가 변할 수 있음(가변적)

 

힙 영역

  • 프로그램을 만드는 사용자, 즉 프로그래머가 직접 할당할 수 있는 저장 공간
  • 참고 )
    • 메모리를 할당 한 뒤 사용을 마치면 할당한 이 메모리 공간을 반환해야함
    • 요즘은 프로그래밍 언어가 대신 반환해주는데 이것을 garbage collection 이라고 함
    • C언어와 같은 옛날 프로그래밍 언어는 가비지 콜렉션 기능이 없어서 직접 메모리를 반환해야 함
    • 반환하지 않으면 계속 메모리 공간을 차지하면서 메모리 낭비를 초래함(메모리 누수 = 메모리 리크)

스택 영역

  • 데이터가 일시적으로 저장되는 공간
  • (데이터 영역에 담기는 값과는 달리) 잠깐 쓰다가 말 값들이 저장되는 공간
  • ex. 매개 변수, 지역 변수

 

힙 영역과 스택 영역의 크기는 가변적

  • 일반적으로 영역은 낮은 주소 → 높은 주소로 할당
  • 일반적으로 스택 영역은 높은 주소 → 낮은 주소로 할당
  • 영역 충돌, 주소가 겹칠 일이 거의 없음 

 

 


프로세스 상태

* 운영체제마다 조금씩 차이가 있지만, 대표적으로는~

 

  • 생성 상태
  • 준비 상태
  • 실행 상태
  • 대기 상태
  • 종료 상태

 

 

상태 자세히 보기

  • 생성 상태 (New State)
    • 이제 막 메모리에 적재되어 PCB를 할당 받은 상태
    • 준비가 완료되었다면 준비 상태로 바뀜
  • 준비 상태 (Ready State)
    • 당장이라도 CPU를 할당 받아 실행할 수 있지만, 자신의 차례가 아니기에 기다리는 상태
    • 자신의 차례가 된다면 실행 상태로 바뀜(=디스패치, dispatch)
  • 실행 상태 (Running State)
    • CPU를 할당 받아 실행 중인 상태
    • 할당된 시간 모두 사용 시(타이머 인터럽트 발생 시) 준비 상태로 바뀜
    • 실행 도중 입출력 장치를 사용하면 입출력 작업이 끝날 때까지 대기 상태로 존재 
  • 대기 상태 (Block State)
    • 프로세스가 실행 도중 입출력장치를 사용하는 경우
    • 입출력 작업은 CPU에 비해 느리기 때문에 이 경우 대기 상태로 접어듬(CPU를 계속 점거하는 것은 낭비니까)
    • 입출력 작업이 끝나면(입출력 완료 인터럽트를 받으면) 준비 상태로 바뀜 
  • 종료 상태 (Terminated State)
    • 프로세스가 종료된 상태
    • PCB, 프로세스의 메모리 영역 정리

 

 

 

 


프로세스 계층 구조


 

* 윈도우 운영체제는 프로세스를 계층적으로 관리하지 않음. 하지만 많은 개발자들이 사용하는 리눅스나 맥OS, 유닉스 등은 프로세스를 계층적으로 운영하기 때문에 알아둬야 함.

 

 

  • 프로세스는 실행 도중 (시스템 호출을 통해) 또다른 프로세스 생성 가능
  • 이때 새 프로세스를 생성한 프로세스를 부모 프로세스(parent process)
  • 부모 프로세스에 의해 생성된 프로세스를 자식 프로세스(child process)

  • 부모 프로세스와 자식 프로세스는 별개의 프로세스이므로 각기 다른 PID를 가짐
  • 일부 운영체제에서는 자식 프로세스 PCB에 부모 프로세스 PID(PPID, Parent PID)를 명시하기도 함

  • 자식은 자식을 낳고, 또 그 자식은 자식을 낳고... 
  • 이 과정이 반복되며 프로세스의 계층적인 구조가 형성됨

 

데몬 프로세스도 컴퓨터가 부팅될 때 실행되는 최초의 프로세스의 자식 프로세스

 

 

 

최초의 프로세스

systemd(시스템 D), launchd

 

 

 


 

프로세스 생성 기법

부모 프로세스는 자식 프로세스를 어떻게 만들어 내고, 자식 프로세스는 어떻게 자신만의 코드를 실행할까?

=> 복제와 옷 갈아입기

 

*Windows 운영체제와는 큰 관련이 없음

 

 

fork와 exec


  • 부모 프로세스는 fork 시스템 호출을 통해 자신의 복사본을 자식 프로세스로 생성
  • 자식 프로세스는 exec 시스템 호출을 통해 자신의 메모리 공간을 다른 프로그램으로 교체

 

 

fork 시스템 호출

  • 복사본(=자식 프로세스) 생성
  • 부모 프로세스의 자원 상속

엄연히 별개의 프로세스이므로 PID와 저장되어있는 메모리 위치 등은 다름

 

 

 

exec 시스템 호출

  • 메모리 공간을 새로운 프로그램으로 덮어쓰기
  • 코드/데이터 영역은 실행할 프로그램 내용으로 바뀌고 나머지 영역은 초기화

 

  • 예시
    1. 사용자가 bash shell 에서 ls라고 하는 명령어를 입력
    2. bash shell 프로세스는 fork 시스템 호출, 복제본 프로세스(자식 프로세스) 생성
    3. exec 시스템 호출을 통해 ls라고 하는 명령어를 실행하기 위한 프로세스로 전환됨 

 

 

  • 프로세스를 생성하고, 계층 구조를 이루는 과정은 fork 시스템 호출과 exec 시스템 호출이 반복되는 과정
  • 물론 fork 시스템 호출까지만 하고 exec 시스템 호출을 하지 않는 경우도 있음 

 

 

 

새로운 프로세스를 만들어내고 새로운 프로그램을 만들어내는 대표적인 과정임

 

 

 

 


스레드(thread)

  • 프로세스를 구성하는 실행 흐름의 단위
  • 하나의 프로세스는 하나 이상의 스레드를 가질 수 있다

 

 

  • 단일 스레드 프로세스
    • 실행 흐름이 하나인 프로세스
  • 멀티 스레드 프로세스
    • 실행 흐름이 여러 개인 프로세스
    • 프로세스를 이루는 여러 명령어 동시 실행 가능

 

 

스레드의 구성 요소

  • 스레드 ID, 프로그램 카운터를 비롯한 레지스터 값, 스택 등 실행에 필요한 최소한의 정보 

  • 3개의 쓰레드로서 병행 실행되는 프로세스 
  • 스레드마다 각기 다른 스택 영역과 프로그램 카운터를 가지고 있어서 스레드마다 서로 각기 다른 프로그램에 있는 부분들을 실행할 수 있음 
  • 프로세스를 이루는 각각의 스레드들은 프로세스의 자원을 공유하면서 실행
    • 스레드1,2,3 모두 똑같은 코드 영역, 데이터 영역을 공유하고 있음
    • 프로세스가 어떤 파일을 열었다면 각각의 스레드는 모두 그 열린 파일에 접근할 수 있음

 

 

참고 : 리눅스 운영체제에서의 스레드

 

참고)

많은 운영체제에서는 프로세스와 스레드를 구분해서 사용하지만,

리눅스에서는 프로세스와 스레드를 똑같은 실행의 문맥으로 생각함

그래서 프로세스와 스레드 대신에 태스크라는 용어로 사용함

 

실제로도 CPU한테 처리해야 될 작업을 전달 할 때
요즘 운영체제는 프로세스를 통채로 전달하기보단
스레드 단위로 CPU를 할당받아서 사용하고 할당을 해제하는 식

즉, 스레드 단위로 전달하는 경우가 많음

 

아직까지 전통적인 관점의 전공서에서는
CPU에게 처리해야 할 작업을 전달할 때
프로세스 단위로 전달한다고 되어있지만,
실제로는 스레드 단위라는 걸 참고로만 알아두면 됨!

 


 

멀티 프로세스와 멀티 스레드


 

동일한 작업을 수행하는
단일 스레드 프로세스 여러 개
vs
하나의 프로세스를
여러 스레드로 실행

 

(좌) fork 3번 실행

 

멀티 프로세스

  • 프로세스를 fork하면 코드/데이터/힙 영역 등 모든 자원이 복제되어 저장됨
  • 저장된 메모리 주소를 제외하면 모든 것이 동일한 프로세스 두 개가 통째로 메모리에 적재
  • fork를 세번 네번 하면 메모리에는 같은 프로세스가 통째로 세개 네개 적재됨
    • 참고)
      fork 직후 같은 프로세스를 통째로 메모리에 중복 저장하지 않으면서 동시에 프로세스끼리 자원을 공유하지 않는 방법도 있음 (쓰기 시 복사, copy on write)

 

 

멀티 스레드

  • 스레드들은 각기 다른 스레드 ID, (별도의 실행을 위해 꼭 필요한) 프로그램 카운터 값을 포함한 레지스터 값, 스택을 가질 뿐 프로세스가 가지는 자원을 공유함 
  • 그렇기 때문에 자원이 변경된다 해도 각각의 스레드들은 그 변경을 바로바로 알아챌 수 있음
  • 하지만 하나의 스레드에 문제가 생기면, 자원을 공유하고 있기 때문에 전체 프로세스에 문제가 생길 수 있음

 

 

 

정리

  • 프로세스 끼리는 자원을 공유하지 않는다 → 남남처럼 독립적으로 실행된다
  • 스레드는 프로세스의 자원을 공유한다 → 협력과 통신에 유리하다. 하지만 때때로 문제가 생길 수 있다 

 

 

참고 : 프로세스 간 통신(IPC, Inter Process Communication)

  • 프로세스끼리는 자원을 공유하지 않음
  • 하지만 프로세스 간에도 자원을 주고 받을 수 있는데, 이를 프로세스 간 통신(IPC)이라고 함
  • 파일을 통한 프로세스 간 통신
    • 프로세스 A가 hello.txt라고 하는 텍스트 파일에 새로운 값 쓰기
    • 프로세스 B가 hello.txt 파일 읽기
    • hello.txt 파일을 통해 서로 통신을 주고 받았다 할 수 있음
  • 공유 메모리를 통한 프로세스 간 통신
    • 공유 메모리에 전역변수 name 값을 저장
    • 프로세스 A가 name에다가 어떤 값 입력
    • 프로세스 B는 그 공유 메모리 안에 name 변수를 읽음 
  • 이외에도 소켓, 파이프 등 다양한 통신 기법들이 있음 

 

 

 

출처 : 혼자 공부하는 컴퓨터구조 + 운영체제 (저자 강민철)