본문으로 건너뛰기

프로세스와 스레드

1. 운영체제 기법의 발전사

운영체제는 하드웨어의 발전과 사용자 요구사항의 변화에 따라 다양한 처리 방식으로 진화해왔다.

세대시스템 유형주요 특징
1세대일괄 처리 시스템 (Batch-processing System)데이터를 일정량 모아 한 번에 처리하는 방식. CPU 유휴 시간은 줄어들지만, 반환 시간(turnaround time)이 길다.
2세대다중 프로그래밍 시스템 (Multi-programming System)하나의 CPU로 여러 프로그램을 동시에 처리. CPU가 유휴 상태일 때 다른 작업으로 전환(인터리빙)하여 CPU 사용률과 처리량을 높인다.
다중 처리 시스템 (Multi-processing System)여러 개의 CPU가 하나의 메모리를 공유하여 작업을 동시에 처리. 속도와 신뢰성이 높다.
실시간 처리 시스템 (Real-time Processing System)데이터 입력 즉시 처리하여 결과를 반환. 좌석 예약, 온라인 뱅킹 등에 사용되며, 정해진 시간 내 완료를 보장하는 Hard와 우선순위만 보장하는 Soft로 나뉜다.
시분할 시스템 (Time-sharing System)다중 프로그래밍을 확장하여 여러 사용자가 대화형으로 작업. CPU 시간을 잘게 나누어(time slice) 할당하는 라운드 로빈(Round Robin) 방식을 사용한다.
3세대다중 모드 처리 시스템 (Multi-mode System)일괄 처리, 시분할, 다중 처리, 실시간 처리 등 여러 방식을 하나의 시스템에서 모두 제공한다.
4세대분산 처리 시스템 (Distributed Processing System)여러 컴퓨터를 네트워크로 연결하여 작업을 분산 처리. 자원 공유, 처리 속도, 신뢰성을 향상시키는 것을 목적으로 한다.
클라우드 컴퓨팅 (Cloud Computing)IT 자원(컴퓨팅, 스토리지 등)을 네트워크를 통해 필요할 때마다 사용하고, 사용한 만큼 비용을 지불하는 서비스 모델이다.

2. 프로세스의 이해

2.1. 프로세스의 개념과 정의

  • 프로그램(Program): 저장장치에 저장된 정적인 코드의 집합. (예: 레시피)
  • 프로세스(Process): 실행을 위해 메모리에 적재된 동적인 상태. 컴퓨터 내에서 실행 중인 프로그램이며,
    운영체제가 관리하는 작업의 기본 단위이다. (예: 레시피에 따라 진행 중인 요리)

프로세스는 단순히 프로그램 코드뿐만 아니라, 실행 상태와 관련된 정보를 포함하는 능동적인 개체(active entity)이다.
운영체제는 각 프로세스를 식별하고 관리하기 위해 프로세스 제어 블록(PCB) 을 사용한다.

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

PCB는 운영체제가 프로세스를 관리하기 위해 필요한 모든 정보를 담고 있는 자료구조로,
작업 지시서에 비유할 수 있다. 프로그램이 프로세스로 전환된다는 것은 운영체제로부터 PCB를 할당받았음을 의미한다.

프로세스 = 프로그램 + PCB

PCB에 저장되는 주요 정보는 다음과 같다.

  • 프로세스 구분자 (PID): 각 프로세스를 식별하는 고유 번호.
  • 프로세스 상태 (Process State): 현재 프로세스가 어떤 상태에 있는지 (준비, 실행 등).
  • 프로그램 카운터 (Program Counter): 다음에 실행할 명령어의 주소.
  • 레지스터 정보: CPU 레지스터의 값 (누산기, 인덱스 레지스터 등).
  • 메모리 관리 정보: 프로세스가 할당받은 메모리 공간의 위치 및 범위 정보.
  • 스케줄링 정보: 프로세스 우선순위, CPU 점유 시간 등.
  • 계정 정보: CPU 사용 시간, 계정 번호 등.
  • 입·출력 상태 정보: 프로세스에 할당된 입출력 장치 및 파일 목록.

2.3. 프로세스의 상태 변화

프로세스는 실행 과정에서 여러 상태를 거치며 변화한다. 이를 프로세스 상태 천이(transition) 라고 한다.

  1. 생성 (New/Create): 프로그램이 메모리에 적재되고 PCB가 생성된 상태.
  2. 준비 (Ready): CPU를 할당받기를 기다리는 상태. 준비 상태의 프로세스들은 준비 큐(Ready Queue)에서 대기한다.
  3. 실행 (Running): CPU 스케줄러에 의해 선택되어 CPU를 할당받고 명령어를 실행하는 상태.
  4. 대기 (Wait/Blocked): 입출력(I/O) 작업과 같이 특정 이벤트가 완료되기를 기다리는 상태.
  5. 완료 (Terminated): 프로세스 실행이 끝나고 메모리에서 제거되기 전의 상태. 이 단계에서 PCB도 삭제된다.

주요 상태 천이 용어:

  • 디스패치 (Dispatch): 준비 상태의 프로세스 중 하나를 선택하여 실행 상태로 전환하는 것.
  • 타임아웃 (Timeout): 할당된 시간(Time Slice)을 모두 소진한 프로세스가 다시 준비 상태로 돌아가는 것.
  • 블록 (Block): 실행 중인 프로세스가 입출력을 요청하여 대기 상태로 전환되는 것.
  • 웨이크업 (Wake up): 입출력 작업이 완료되어 대기 상태의 프로세스가 준비 상태로 전환되는 것.

이 외에도 메모리가 부족할 때 프로세스를 잠시 디스크로 내보내는 보류(Suspend) 상태가 있다.

3. 프로세스 관리와 문맥 교환

3.1. 프로세스 연산: 생성, 전환, 계층 구조

  • fork() 시스템 호출 (생성 및 복사):

    • 실행 중인 프로세스(부모 프로세스)가 자신과 거의 동일한 새로운 프로세스(자식 프로세스)를 생성하는 함수.
    • PCB를 포함한 대부분의 메모리 영역이 복사되지만, PID와 같은 일부 정보는 새로 부여된다.
    • fork()는 부모 프로세스에는 양수(자식의 PID)를, 자식 프로세스에는 0을 반환한다.
    • 장점: 프로세스 생성 속도가 빠르고, 부모의 자원을 상속받아 시스템 관리가 효율적이다.
  • exec() 시스템 호출 (전환):

    • 기존 프로세스의 메모리 공간을 새로운 프로그램으로 덮어쓰는 함수.
    • 프로세스는 그대로 유지되지만, 코드, 데이터, 스택 영역의 내용이 완전히 교체된다.
    • PID와 같은 PCB의 핵심 정보는 유지되므로, 기존 프로세스를 '재활용'하는 개념이다.
  • 프로세스 계층 구조:

    • 유닉스(Unix) 시스템에서 모든 프로세스는 최초의 init 프로세스로부터 파생된 트리 구조를 형성한다.
    • 고아 프로세스 (Orphan Process): 부모 프로세스가 먼저 종료되어 돌아갈 곳이 없는 자식 프로세스.
    • 좀비 프로세스 (Zombie Process): 자식 프로세스가 종료되었으나 부모가 뒤처리를 하지 않아 PCB가 메모리에 남아있는 상태. exit() 호출로 부모에게 종료를 알리고, 부모는 wait()로 자원을 회수해야 한다.

3.2. 문맥 교환 (Context Switching)

문맥 교환은 하나의 프로세스가 사용하던 CPU를 다른 프로세스에게 넘겨주기 위해 발생하는 절차이다.

  1. 현재 실행 중인 프로세스의 상태 정보(문맥)를 해당 프로세스의 PCB에 저장한다.
  2. 다음에 실행할 프로세스의 PCB로부터 문맥을 CPU 레지스터에 적재(load)한다.
  3. 새로운 프로세스의 실행을 시작한다.

이 과정은 CPU를 차지하던 프로세스가 나가고 새로운 프로세스가 들어오는 것으로,
다중 프로그래밍의 핵심 동작이다. 문맥 교환 자체는 오버헤드(overhead)를 발생시키므로,
타임 슬라이스의 크기를 너무 작게 설정하면 문맥 교환 비용이 커져 시스템 효율이 저하될 수 있다.

4. 스레드의 개념과 활용

4.1. 스레드의 정의와 특징

  • 스레드(Thread): 프로세스 내에서 작업을 수행하는 실행 흐름의 단위. CPU 입장에서의 작업 단위이다.
  • 경량 프로세스 (Lightweight Process): 하나의 프로세스는 여러 개의 스레드를 가질 수 있다.
    이 스레드들은 프로세스의 자원(코드, 데이터, 힙 영역)을 공유하지만, 각자 독립적인 스택(Stack)과 레지스터 값을 가진다.
구분 멀티태스킹 멀티스레딩

개념 여러 개의 프로세스가 동시에 실행 하나의 프로세스 내에서 여러 개의 스레드가 동시에 실행
자원 공유 프로세스 간 메모리 공유가 어려움 (IPC 필요) 스레드 간 코드, 데이터, 힙 영역 공유
오버헤드 문맥 교환 시 오버헤드가 큼 스레드 간 전환 시 오버헤드가 적음

4.2. 멀티스레드의 장점과 단점

  • 장점:

    • 응답성 향상: 한 스레드가 대기 상태에 있어도 다른 스레드는 계속 실행 가능.
    • 자원 공유: 메모리 및 자원을 공유하므로 통신이 쉽고 효율적.
    • 효율성 향상: 스레드 생성 및 전환 비용이 프로세스보다 적다.
    • 다중 CPU 지원: 여러 CPU에서 스레드를 병렬로 실행하여 성능을 극대화할 수 있다.
  • 단점:

    • 자원을 공유하기 때문에 하나의 스레드에 문제가 발생하면 전체 프로세스에 영향을 미칠 수 있다.
    • 동기화(Synchronization) 문제가 발생할 수 있어 신중한 설계가 필요하다.

4.3. 멀티스레드 모델

사용자 수준 스레드를 커널 수준 스레드에 어떻게 매핑하는지에 따라 세 가지 모델로 나뉜다.

  1. 사용자 수준 스레드 (Many-to-One 모델):

    • 여러 개의 사용자 스레드가 하나의 커널 스레드에 매핑된다.
    • 사용자 공간의 라이브러리에 의해 관리되므로 스레드 전환 속도가 빠르다.
    • 단점: 하나의 스레드가 시스템 호출 등으로 대기 상태가 되면 모든 스레드가 대기하게 되며, 다중 CPU를 활용할 수 없다.
  2. 커널 수준 스레드 (One-to-One 모델):

    • 사용자 스레드 하나가 커널 스레드 하나에 직접 매핑된다.
    • 커널이 직접 스케줄링하므로 하나의 스레드가 대기해도 다른 스레드는 계속 실행 가능하다.
    • 다중 CPU를 효율적으로 활용할 수 있다.
    • 단점: 스레드 전환 시 커널 모드로의 전환이 필요해 오버헤드가 크다.
  3. 멀티레벨 스레드 (Many-to-Many 모델):

    • 여러 개의 사용자 스레드를 그보다 적거나 같은 수의 커널 스레드에 매핑하는 혼합 방식.
    • 두 모델의 장점을 결합하여 유연성과 효율성을 동시에 추구한다.

5. 프로세스 메모리 구조와 주요 시스템 호출

5.1. 동적 할당 영역

프로세스의 메모리 공간은 크게 정적 할당 영역동적 할당 영역으로 나뉜다.

  • 정적 할당 영역:

    • 코드(Code) 영역: 실행할 프로그램의 코드가 저장되는 공간. 읽기 전용.
    • 데이터(Data) 영역: 전역 변수와 정적 변수가 저장되는 공간.
  • 동적 할당 영역:

    • 힙(Heap) 영역: 프로그래머가 직접 관리하는 메모리 공간. malloc(), calloc() 등으로 할당된다.
    • 스택(Stack) 영역: 함수 호출 시 지역 변수, 매개변수, 반환 주소 등이 저장되는 공간. 함수가 종료되면 자동으로 사라진다.

5.2. 핵심 시스템 호출: 와

  • exit() 시스템 호출:
    • 프로세스의 종료를 운영체제 및 부모 프로세스에 알리는 함수.
    • 자식 프로세스는 exit()를 호출하여 자신이 사용하던 자원을 부모가 회수할 수 있도록 한다.
    • 반환값(인자)을 통해 정상 종료(0)인지 비정상 종료(-1)인지 상태를 전달한다.
  • wait() 시스템 호출:
    • 부모 프로세스가 자식 프로세스가 종료될 때까지 기다리게 하는 함수.
    • 자식 프로세스가 종료되면 wait()는 반환되며, 부모는 자식의 종료 상태를 확인하고 관련 자원을 정리한다.
    • 프로세스 간의 동기화를 위해 사용된다. 전면(foreground) 프로세스는 wait()를 사용해 자식이 끝날 때까지 대기하지만, 후면(background) 프로세스(&)는 wait() 없이 즉시 다음 명령을 받는다.