프로세스와 쓰레드

프로세스와 쓰레드의 역할의 차이를 잘 알아야 한다. 먼저, 프로세스는 실행의 단위이며 쓰레드는 작업의 흐름이란 것을 잘 기억하자. 프로세스는 하나의 프로그램을 의미한다. 그래서 실행의 단위라고 하며, 프로세스는 CPU가 하나만 실행할 수 있다. 가장 큰 특징은 스레드와 비교하면 프로세스는 독립된 자원 공간을 사용한다.

프로세스 메모리 구조

주소 값은 상단 (높은 주소) → 하단 (낮은 주소)이다.

프로세스는 OS로 부터 메모리 영역을 할당 받는다. 메모리에는 코드, 데이터, 스택, 힙등이 있다. 메모리 구조는 위에 이미지와 같이 저장된다고 보면 된다.

  • 스택 : 지역 변수, 함수의 매개변수, 반환되는 주소 값 등이 저장되는 영역. 스택은 빈공간이 있는 아래쪽으로 저장된다.
  • 힙 : 동적 메모리 할당이 일어나는 영역이다. 힙은 반대로 빈공간이 있는 위쪽으로 저장된다.
  • 데이터 : 전역 변수, 정적 변수, 배열, 구조체가 저장되는 영역, 세부적으로 BSS(Block Stated Symbol)라고 초기화 되지 않은 변수도 저장한다.
  • 코드 : 실행할 코드들이 저장된다.

스택 또는 힙공간 사이에 빈공간이 차면 나오는 에러가 스택오버 또는 힙 오버플로우가 에러이다.

오버 플로우에 반대되는 용어인 언더 플로우가 있고, 언더 플로우는 공간에서 할당할 수 있는 최소 범위보다 작은 것을 의미한다.

쓰레드

쓰레드는 프로세스로부터 파생된다. 프로세스가 여러 개의 쓰레드를 갖게 되는 것이다.
쓰레드는 실행되는 흐름의 단위이다. 프로세스 안에 존재하는 쓰레드는 프로세스의 메모리 공간을 이용하고, 지역 변수를 저장하는 스택 영역을 할당받는다.

그리고 쓰레드는 다른 쓰레드와 공유할 수 있는 역역이 있는데 바로 힙 영역(전역 변수)이다. 중요한 특징은 쓰레드는 다른 쓰레드와 자원을 공유하는 데이터가 많아 프로세스와 비교했을 때 오버헤드가 덜 일어난다.

오버헤드 : 컨텍스트 스위칭이 일어날 때 CPU가 잠시동안 작업을 멈추는 시간을 말한다.

사용자 레벨 쓰레드, 커널 레벨 쓰레드

쓰레드도 커널 모드와 사용자 모드로 나뉜다.
사용자 레벨 쓰레드는 사용자가 라이브러리를 이용해 생성 및 관리한다.
커널 레벨 쓰레드는 커널이 쓰레드를 생성 및 관리한다.


사용자 레벨 쓰리드와 커널 레벨 쓰레드는 다음과 같이 3가지 관계를 맺는다.

1. 다대일 모델

사용자 레벨 n개에 커널 레벨 1개가 매핑 하나의 사용자 레벨 쓰레드가 커널 레벨 쓰레드를 호출하면 다른 쓰레드는 그동안 사용을 하지 못한다.

  • 스레드 관리는 사용자 공간에 스레드 라이브러리에 의해 행해진다.

  • 장점
    1. 커널 모드를 호출할 때 이벤트 콜이 발생해서 오버헤드가 발생하는데 커널모드가 하나이기 때문에 사용자 스레드 생성 및 관리에 대한 오버헤드가 줄어든다.
    2. 스레드 간의 통신 및 동기화가 간단해진다.
  • 단점
    1. 하나의 커널 레벨 스레드에 의해 처리 되어 사용자 레벨 스레드의 응답시간이 빠르지만, 커널 레벨 스레드에 발생하는 부하나 병목현상으로 인해 느려질 수 있다.
    2. 커널 스레드 하나에 문제가 발생하면 해당 스레드와 관련된 모든 사용자 스레드가 영향을 받을 수 있다.

2. 일대일 모델

사용자 레벨 쓰레드 하나당 커널 레벨 쓰레드 하나가 할당된다.

  • 장점
    1. 각각의 사용자 스레드가 별도의 커널 스레드에 매핑되므로 병렬 처리가 가능하다.
    2. 안정성이 높고 예측 가능한 동작을 보장한다.
    3. 구현이 간단하다.
  • 단점
    1. 스레드 생성 및 관리에 대한 오버헤드가 발생할 수 있다.
    2. 너무 많은 스레드를 생성할 경우, 시스템 리소스를 낭비할 수 있다.

3. 다대다 모델

사용자 레벨 쓰레드 n개와 커널 모드 쓰레드 m개가 매핑. 1번과 2번의 단점을 보완한 모델이지만, 구현이 어렵다는 단점이 있다.

  • 장점
    1. 병렬 처리가 가능하며, 스레드 간의 통신과 동기화가 유연하게 이루어진다.
    2. 시스템 리소스를 효율적으로 활용할 수 있다.
  • 단점
    1. 구현 및 관리가 복잡하며, 오버헤드가 발생할 수 있다.
    2. 스레드 간의 스케줄링 및 동기화가 관리하기 어려울 수 있다.

프로세스 생명주기

OS가 프로세스를 관리하기 위해 프로세스를 상태 정보를 저장하는데 PCB에 저장된다.

PCB
OS가 프로세스를 제어하기 위한 프로세스 정보를 저장하는 공간.
프로세스의 상태, PID, 부모 PID, 자식 PID, 다음 실행할 명령어 주소(Program Counter), 프로세스 우선순위, 메모리 제한 등을 저장한다.

프로세스 상태

프로세스의 상태는 생성, 준비, 대기, 실행, 종료가 있다.

  • 생성 : 프로세스가 PCB를 가지고, OS 승인을 받기 전
  • 준비 : OS로부터 승인 받고 준비 큐에 대기
  • 실행 : CPU를 할당받고 실행
  • 대기 : 시스템 콜 또는 입출력 이벤트가 발생하여 대기 상태
  • 종료 : 프로세스 종료

프로세스 생성과 종료

프로세스는 기존 프로세스에서 fork() 함수를 통해 생성 가능하다. fork() 함수는 호출한 프로세스를 복사하는 기능이 있다. 기존 프로세스는 부모 프로세스가 되고 복사된 프로세스는 자식 프로세스라 일컫는다.

fork()를 하게 되면 부모프로세스는 자식 프로세스의 PID값을 리턴하고, 자식 프로세스는 0을 리턴한다.

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main() {
    pid_t pid;
    int x = 0;
    
    pid = fork();
    
    if(pid > 0) {  // 부모 코드
        x = 1;
    }
    else if(pid == 0){  // 자식 코드
        x = 2;
    }
    else {  // fork 실패
        return -1;
    }
    printf("PID : %ld, x : %d\n",(long)getpid(), x);
    return 0;
}

다음 과 같은 C언어 코드가 있을 때 fork() 후 반환 값을 확인하면 pid에 따라서 다른 처리를 할 수 있는 것을 볼 수 있다.

프로세스 종료는 다음과 같이 여러 경우를 볼 수 있다.

  • exit() 호출을 통한 정상 종료
  • 실행 시간 또는 특정 이벤트 대기 시간 초과
  • 파일 검색 입출력에 실패
  • 오류 발생 및 메모리 부족


부모 프로세스는 자식 프로세스가 할당된 자원을 초과하거나 자식 프로세스에 할당된 작업이 없을 때 종료 시킬 수 있다.

프로세스 상태 변화

  1. 생성 → 준비 : OS승인을 받아서 준비 큐에 올라감.
  2. 준비 → 실행 : 준비 큐에 있는 프로세스 중 우선순위가 높은 프로세스가 디스패치 되어 CPU에 올라감.
  3. 실행 → 준비 : CPU에 독점 방지를 위해 timeout 된 프로세스를 인터럽트 요청하여 준비 상태로 변경
    1. 예외 사항일 때 - 선점형 스케줄링
  4. 실행 → 대기 : 입출력이나 이벤트를 위해 인터럽트 요청하여 대기 상태가 된다.
    1. 입출력이나 이벤트 - 파일 요청 등
  5. 실행 → 종료 : 프로세스 실행 종료
  6. 대기 → 준비 : 입출력이나 이벤트가 완료되어 준비 상태로 변경

디스패치 : 프로세스에 CPU 자원을 할당해 해당 프로세스가 준비 상태에서 실행 상태가 되는 것을 의미한다.
인터럽트 : 현재 실행되는 작업보다 먼저 급하게 처리해야되는 일이 발생하여 처리되는 경우를 말한다.

멀티 프로세스, 멀티 쓰레드

멀티 프로세스

응용 프로그램 하나를 여러 프로세스로 구성하는 것을 의미

  • 한 프로세스가 죽어도 다른 프로세스에 영향이 없다.
  • 시간과 메모리 공간을 많이 사용한다.
  • CPU는 하나의 작업만 처리 가능하다. 그렇기 때문에 여러 프로세스를 처리하려면 CPU에서 콘텍스트 스위칭 작업을 통해 프로세스를 교체해야 한다.
  • 프로세스는 IPC를 통해 프로세스 간에 자원을 공유할 수 있다.


멀티 쓰레드

쓰레드를 여러 개 생성해 쓰레드들이 각자 다른 작업을 처리하도록 한다.

  • 쓰레드 간에 힙, 데이터, 코드 영역을 공유한다.
  • 콘텍스트 스위칭할 때 오버헤드가 적게 든다. 그렇기 때문에 프로세스보다 효율이 좋다.
  • 자원에 대한 동기화가 필요하다.

동시성과 병렬성
동시성은 하나의 코어에서 여러 작업을 번갈아 가면서 처리하는 방식
병렬성은 CPU가 멀티 코어에 있어서 CPU가 각 작업을 동시에 처리하는 방식


출처

  • 기술 면접 대기 CS 전공 핵심요약집 (책)
  • 패스트 캠퍼스 강의