[운영체제] 프로세스

2025. 4. 16. 07:17·⚙️ CS/운영체제
반응형

✅ 프로세스 (Process)

: 메모리 상에서 실행 중인 프로그램

 

디스크에 저장된 정적인 명령어 집합인 프로그램이 실행되면, 운영체제는 이에 필요한 자원을 할당하고 메모리에 적재한다.

이 시점부터 프로세스라고 부르는 것이다.

 

만약 동일한 프로그램을 여러 번 실행하면, 각각 다른 프로세스가 생성된다.

 

- 프로그램: 정적인 코드
- 프로세스: 실행 중인 프로그램
- 스레드: 프로세스 내 작업 단위

✅ 프로세스의 상태

Process State
출처: "Operating System Concepts", Abraham Silberschatz

 

  • New: 생성 중인 상태
  • Running: 실제로 CPU에서 실행되고 있는 상태
  • Waiting(Blocked): 이벤트가 완료되길 기다리는 상태
  • Ready: 프로세스가 실행될 준비는 되어 있지만, 아직 CPU를 배정받지 못한 상태
  • Terminate: 실행이 완료되어 종료된 상태
  • Suspended: 메모리 부족 등으로 중단된 상태

 

[ Preemptive / Non-preemptive에 따라 존재할 수 없는 상태는? ] 

Preemptive 스케줄링: 운영체제가 CPU를 현재 실행 중인 프로세스에서 강제로 빼앗아 다른 프로세스에 할당하는 방식
Non-Preemptive 스케줄링: 현재 실행 중인 프로세스가 CPU를 자발적으로 반납할 때까지 다른 프로세스에 CPU를 할당하지 않는 방식

Preemptive와 Non-preemptive는 CPU 스케쥴링 알고리즘에서 사용되는 개념이므로,
프로세스의 실행 상태와는 별도로 존재한다.

따라서 Preemptive와 Non-preemptive에서 존재할 수 없는 상태는 따로 존재하지 않는다.

 

[ Memory가 부족할 경우, Process는 어떠한 상태로 변화할까? ]

Process는 더 이상 작업을 수행할 수 없게 되기 때문에 Swap-out 되어 Suspended(Swapped-out) 상태로 전이된다.

이때 메모리 부족으로 필요한 데이터를 가져올 수 없는 경우 Block가 되어 다른 프로세스가 끝나기를 기다리거나,
OS가 프로세스를 강제로 종료시켜 Terminated 상태로 전이된다.

 


📍 프로세스의 생성

실행 중인 프로세스는 여러 개의 새로운 프로세스들을 생성할 수 있다.

 

이때 생성하는 프로세스를 부모 프로세스, 새로운 프로세스를 자식 프로세스라고 부른다.

새로운 프로세스들을 계속 생성하다 보면, 프로세스는 트리를 형성한다.

 

Process Create
출처: "Operating System Concepts", Abraham Silberschatz

 

 

리눅스에서 `fork()` 시스템 콜을 사용하여 프로세스를 생성한다.

그리고 해당 프로세스 내에서 `fork()` 시스템 콜을 사용하면, 함수를 호출한 프로세스를 복사하여 자식 프로세스를 생성한다.

 

`fork()`를 호출하면 부모 프로세스는 자식 프로세스 PID를, 자식 프로세스는 0을 반환한다.

 

반면 스레드는 `pthread_create()` 함수를 호출하여 생성할 수 있다.

 

프로세스의 식별자인 PID는 보통 정수이다.
[ 리눅스에서 루트 노드에 위치하는 프로세스는? ]

리눅스에서 루트 노드에 위치하는 프로세스는 init 또는 systemd이다.
이는 리눅스 부팅 시, 커널에 의해 시작되는 첫 번째 프로세스로 PID 값 1을 가진다.

📍 프로세스의 종료

`exit()` 시스템 콜을 사용하여 프로세스를 종료한다.

프로세스는 종료되면 부모 프로세스에 상태 값을 반환할 수 있다.

 

자식이 먼저 죽을 경우: 좀비 프로세스

  • 자식 프로세스는 좀비 프로세스가 된다.
  • 종료되었지만 부모가 wait()을 호출하지 않으면 PCB는 그대로 남아 있는 것이다.
  • 해결: 부모가 wait() 또는 waitpid()를 호출해 자식의 종료 상태를 수거한다.

 

부모가 먼저 죽을 경우: 고아 프로세스

  • 자식 프로세스는 고아 프로세스가 된다.
  • 리눅스에서는 고아 프로세스를 PID 1번인 init/systemd 프로세스가 입양하여 관리한다.
  • init 또는 systemd: 모든 프로세스의 부모가 되는 최상위 프로세스 

 


 

📍 리눅스의 데몬 프로세스

: 백그라운드에서 동작하며, 사용자와 직접 상호작용하지 않는 서비스형 프로세스

 

시스템 또는 사용자 요청에 따라 특정 서비스를 지속적으로 제공하는 프로세스이다.

주로 서버나 시스템 서비스를 담당하고, 터미널 세션과 완전히 독립된 실행 환경을 갖는다.

 

대표적으로 다음과 같은 프로세스가 있다.

  • sshd: SSH 접속 요청을 대기 및 처리
  • cron: 예약된 작업을 주기적으로 실행
  • httpd: 웹 서버 요청 처리

 

터미널 세션: 사용자가 로그인한 뒤, 쉘을 통해 명령어를 입력하고 출력받는 일련의 입출력 환경

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

: 프로세스에 대한 정보를 담는 운영체제의 자료구조

 

task control block 이라고도 불린다.

 

운영체제는 PCB를 통해 각 프로세스 관리에 필요한 모든 정보(상태, 식별자, 레지스터 값, 메모리 정보 등)를 추적하고 관리한다.

 

PCB
출처: "Operating System Concepts", Abraham Silberschatz

 

  • 프로세스 상태(Process state): new, ready, running, waiting 등
  • 프로그램 카운터(Program Counter): 해당 프로세스에서 다음으로 실행할 명령어 주소
  • 레지스터(registers): CPU 레지스터 상태
  • ID: PID(Process ID), 부모 프로세스 ID(PPID), 사용자 ID(UID), 그룹 ID(GID)

 


✅ 프로세스의 주소 공간

프로세스는 실행을 위해 별도의 주소 공간을 독립적으로 할당받는다.

 

그리고 이 주소 공간을 다음과 같은 구조로 관리한다.

프로세스 주소 공간
출처: "Operating System Concepts", Abraham Silberschatz

 

 

 

  • 스택(stack): 함수 호출 시 사용되는 임시 저장소(지역 변수, 매개변수, 반환 주소 등)
    • 런타임 중 크기가 가변적이다.
    • 지역변수는 초기화되지 않더라도 stack에 저장된다.
    • 함수 호출 시 할당되고, 호출 종료 시 자동 해제된다.
    • 높은 주소에서 낮은 주소 방향으로 할당된다.
    • 힙 영역과 방향이 반대이기 때문에 서로 충돌하지 않도록 OS가 관리해야 한다.
      • 그림 상에서는 스택의 크기가 무한정 확장되는 것처럼 보이지만,
      • OS에서는 스택의 최대 크기 제한을 정해서 할당한다.
  • 힙(heap): 동적 메모리 할당에 사용
    • 런타임 중 크기가 가변적이다.
      • 필요에 따라 동적으로 확장, 축소가 가능하다.
      • 스택의 처
    • 낮은 주소에서 높은 주소 방향으로 할당된다.
  • 데이터(data): 전역 변수 및 정적 변수 저장 (uninitialized data + initialized data)
    • 크기가 고정적이다.
    • 프로그램의 시작과 함께 할당되며, 프로그램이 종료되면 소멸한다.
    • 초기화하지 않은 변수는 데이터 영역의 일부인 BSS(Block Started by Symbol) = unitialized data에 저장된다.
      • 프로그램이 시작될 때 자동으로 0으로 초기화된다.
  • 텍스트(text = code): 실행할 프로그램의 기계어 코드 저장
    • 크기가 고정적이다.

즉 프로세스는 독립적으로 동작하며, 다른 프로세스의 메모리에는 직접 접근할 수 없다.

 

프로세스는 다른 코드를 실행하기 위한 실행 환경이 될 수 있다.

대표적 예로, JVM도 하나의 프로세스이다.

 

[스택과 힙은 자료구조와 연관이 있을까?]
1. 스택(O)
함수 호출 시 스택 프레임(매개변수, 지역 변수 등)이 쌓임
후입선출(LIFO)로 가장 최근 호출한 함수부터 복귀
주소는 상위 주소 → 하위 주소 방향으로 확장

2. 힙(X)
자료구조의 Heap과는 이름만 같고 동작 방식은 다름
주소는 하위 주소 → 상위 주소 방향으로 확장

 


✅ 프로세스 스케줄러 

운영체제는 프로세스를 스케줄링하기 위해 다음과 같이 세 가지의 Queue를 사용한다.

  1. Job Queue : 현재 디스크 상에 대기 중인 모든 작업
  2. Ready Queue : 현재 메모리 내에 있으면서 CPU를 잡아서 실행되기를 기다리는 프로세스의 집합
  3. Device Queue : Device I/O 작업을 대기하고 있는 프로세스의 집합

각각의 Queue에 대한 스케줄러에도 다음과 같이 세 가지 종류가 있다.

 


📍 단기 스케줄러 (Short-term Scheduler = CPU Scheduler)

: Ready Queue에서 실행할 프로세스를 CPU에 할당

 

  • CPU와 메모리 사이의 스케줄링을 담당하여 CPU 스케줄러라고도 불린다.
  • Ready Queue에 존재하는 프로세스 중 어떤 프로세스를 running 시킬지를 결정한다.
  • 실행 빈도가 가장 높다.
  • 프로세스 상태: ready -> running -> waiting -> ready

 


📍 중기 스케줄러 (Medium-term Scheduler = Swapper)

: 메모리 관리 관점에서 프로세스를 Swap-out 시켜 일시 정지 상태로 이동시킴

 

  • 메모리 부족 시 사용된다.
  • 여유 공간 마련을 위해 프로세스를 통째로 메모리에서 디스크로 쫓아낸다.(swapping)
  • 즉, 프로세스에게서 메모리를 deallocate 한다.
  • 메모리에 너무 많은 프로그램이 동시에 올라가는 것을 조절하는 스케줄러라고 할 수 있다.
  • 프로세스 상태: ready -> suspended

 

Suspended(stopped)
: 외부적인 이유로 프로세스의 수행이 정지된 상태로 메모리에서 내려간 상태

프로세스가 디스크로 swap out 된다.
외부적인 이유로 suspending 되었기 때문에 스스로 돌아갈 수 없다.
( blocked 상태는 다른 I/O 작업을 기다리는 상태이기 때문에 스스로 ready state로 돌아갈 수 있다 )

📍 장기 스케줄러 (Long-term Scheduler = Job Scheduler)

: 디스크에 있는 프로세스 중 어떤 프로세스에 메모리를 할당하여 Ready Queue로 보낼지 결정

 

  • 메모리와 디스크 사이의 스케줄링을 담당한다.
  • 프로세스에 메모리를 할당(admit)한다.
  • degree of Multiprogramming(실행 중인 프로세스의 수)를 제어한다.
  • CPU-bound와 I/O bound 비율을 조절해 시스템 부하를 조절한다.
  • 프로세스 상태: new -> ready

 

[ 현대 OS에는 단기, 중기, 장기 스케쥴러를 모두 사용하고 있나? ]

현대 운영체제에서는 단기 스케줄러는 항상 사용되며,
중기/장기 스케줄러는 일부 시스템(ex. 배치 시스템)에서만 명시적으로 작동한다.

 


✅  Context Switching (문맥 교환)

: CPU가 이전의 프로세스 상태를 PCB에 보관하고, 또 다른 프로세스의 정보를 PCB에서 읽어 레지스터에 적재하는 과정

 

Context Switching
출처: "Operating System Concepts", Abraham Silberschatz

 

  1. precess p0에서 interrupt나 System call을 만나면 PCB0에 프로세스의 정보가 저장이 된다.
  2. precess p1의 정보를 가지고 오고, 상태를 변경하여 cpu에 할당한다.
  3. precess p1에서 interrupt나 System call을 만나면 PCB1에 프로세스의 정보가 저장이 된다.
  4. precess p0의 정보를 가지고 오고, 상태를 변경하여 cpu에 할당한다.

 


 

📍 User Stack & Kernel Stack

프로세스는 모드분리와 마찬가지로 시스템을 보호하기 위해 User Stack과 Kernel Stack을 가진다.

  • User Stack: 사용자 모드에서 함수 호출, 지역 변수 등을 위한 공간
  • Kernel Stack: 시스템 콜, 인터럽트, 컨텍스트 스위칭 등 커널 모드에서의 처리에 사용

 

그리고 컨텍스트 스위칭이 발생하면, 기존의 프로세스 정보는 Kernel Stack에 저장된다.

앞서, PCB에 프로세스 정보를 저장한다고 했는데 Kernel Stack은 그 PCB의 일부라고 할 수 있다.

 

  1. interrupt 발생
  2. 현재 실행 중인 프로세스 → 커널 모드 진입
  3. 커널 스택에 레지스터 값 등 상태 저장
  4. 스케줄러가 새로운 프로세스 선택
  5. 새 프로세스의 상태 복원
  6. 새 프로세스 실행

 


 

📍 발생하는 시점

컨텍스트 스위칭은 다음과 같은 상황에서 일어난다.

  • I/O 요청: 현재 실행 중인 프로세스가 I/O 요청을 하면 CPU는 다른 Ready 프로세스를 실행
  • 프로세스 종료: 실행 중인 프로세스가 종료되면 다음 프로세스 실행
  • 인터럽트 발생: 현재 작업 상태 저장 후, 인터럽트 핸들러 실행 후 다른 프로세스로 전환
  • 선점형 스케줄링: 높은 우선순위의 프로세스가 등장하면, 해당 프로세스로 전환

 

📍 문제점

Context Switching이 잦으면 오버헤드(Overhead) 비용이 발생하여 성능이 떨어진다.

 

실행할 프로세스의 정보를 PCB에서 가지고 올 동안 CPU가 아무런 일을 하지 못하게 되어 시간이 낭비된다.

 

보통 다음과 같은 무거운 작업이 진행되면 오버헤드 비용이 발생할 수 있다.

  • Cache 초기화
  • Memory mapping 초기화
오버헤드: 사용된 시간과 메모리의 양

 

📍해결 방안

여러 프로세스에 Context Switching 하지 말고, 단일 프로세스에 여러 스레드를 생성하면 된다.

즉, 스레드에서 Context Switching을 하는 것이다.

 

스레드는 메모리 공간을 공유하고 있어, 프로세스보다 Context Swtiching 비용이 적게 든다.

반응형

'⚙️ CS > 운영체제' 카테고리의 다른 글

[운영체제] 동기화  (0) 2025.04.29
[운영체제] 스케줄링  (0) 2025.04.28
[운영체제] 스레드  (1) 2025.04.16
[운영체제] 시스템 콜 & 인터럽트  (0) 2025.04.15
'⚙️ CS/운영체제' 카테고리의 다른 글
  • [운영체제] 동기화
  • [운영체제] 스케줄링
  • [운영체제] 스레드
  • [운영체제] 시스템 콜 & 인터럽트
dev-heyjin
dev-heyjin
  • dev-heyjin
    개발 기록
    dev-heyjin
  • 전체
    오늘
    어제
    • 분류 전체보기 (56)
      • 🎯 Programming (8)
      • 💪 Algorithm (16)
      • ⚙️ CS (31)
        • 네트워크 (15)
        • 운영체제 (15)
        • 데이터베이스 (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    데이터베이스
    DB
    RDS
    해킹
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
dev-heyjin
[운영체제] 프로세스
상단으로

티스토리툴바