# Table of Contents

# 프로세스

  • 메모리에 로드되어 연속적으로 실행되고 있는 프로그램
  • 네 가지 영역으로 구분된다.
    • Code: 컴파일된 코드가 저장되는 영역
    • Data: 전역변수, Static 변수가 저장되는 영역
    • Stack: 지역변수, 매개변수가 저장되는 영역
    • Heap: 동적 할당 영역

# PCB

  • Process Control Block
  • 멀티 프로세스 환경에서 각 프로세스를 구분하기 위해 운영체제가 유지하고 있는 프로세스 정보
  • 운영체제가 Context Switching을 할 때 필요로 한다.
  • PID, 상태, 스케줄링 우선순위 등의 정보를 저장한다.

# 스레드

  • 프로세스의 실행 흐름
  • 하나의 프로세스는 여러 실행 흐름을 가질 수 있으며, 이를 멀티 스레드라고 한다.
  • 모든 스레드는 Code, Data, Heap영역을 공유하지만 각각의 Stack을 사용한다.

# 인터럽트

  • 한 프로세스가 실행 중일 때 다른 프로세스를 실행하기 위하여 현재 프로세스를 중지하거나, 입출력에 의해 현재 프로세스를 중단시키는 것
  • 인터럽트의 처리과정
    1. 인터럽트가 발생하면 운영체제가 현재의 프로세스 상태를 저장하고 인터럽트를 처리한다.
    2. 이전 프로세스로 복구한다.

# Context Switching

  • 현재 프로세스 (또는 스레드)의 상태를 저장하고 다른 프로세스 (또는 스레드)로 제어권을 넘기는 작업

# 멀티 프로세스 대신 멀티 스레드

  • 멀티 프로세스의 Context Swtiching 비용이 더 크다.
  • 멀티 스레드는 Stack 영역만 스위칭하면 되지만 멀티 프로세스는 Code, Data, Heap 영역까지 스위칭해야하기 때문이다.

# 공유 자원과 임계 영역

  • 멀티 프로세스 (또는 멀티 스레드) 환경에서는 여러 프로세스가 하나의 자원에 접근할 수 있다. 이를 공유 자원이라고 한다.
  • 공유 자원에 접근하는 코드를 임계 영역(Critical Section)이라고 한다.
  • 공유 자원은 한 순간에 하나의 프로세스만 접근할 수 있도록 해야하는데 동기화해야 한다.

# 동기화

  • 멀티 스레드 환경에서 한 순간에는 하나의 스레드만 공유자원에 접근할 수 있도록 하는 것.
  • 동기화에는 다음과 같은 방법이 있다.

# Mutex, Semaphore

둘 다 한 순간에 여러 프로세스, 스레드가 동시에 공유자원에 접근하지 못하도록 하는 기법이다.

  • Mutex:
    • Locking 메커니즘
    • Mutex는 0 또는 1 값만 올 수 있는 정수형 변수다.
    • 프로세스가 Mutex를 확인한 후 0이면 Mutex를 1로 설정한 후 공유 자원에 접근한다. 프로세스가 Mutex를 확인한 후 1이면 Mutex가 0이 될 때까지 확인하면서 기다린다.
    • 결국 Mutex는 한 순간에 하나의 프로세스, 스레드만 공유자원에 접근하도록 한다.
    • 이진 세마포어라고도 한다.
  • Semaphore
    • Signaling 메커니즘, 즉 wait()과 signal() 메소드를 사용한다.
    • Semaphore는 내부에 정수형 변수 N을 유지하고 있는 객체다.
    • 프로세스가 변수가 N보다 작은지 확인한 후 N보다 작으면 N+1로 설정 후 공유자원에 접근한다. 프로세스가 변수 N을 확인한 후 N이면 N보다 작아질 때까지 기다린다. 공유자원을 사용 중인 프로세스는 자원을 다 사용하면 기다리고 있는 프로세스들에게 신호를 보낸다.
    • 결국 Semaphore는 정해진 수 만큼의 프로세스만 공유자원에 접근하도록 한다.

# 데드락

  • 프로세스들이 서로의 자원을 점유한 상태에서 상대방의 자원을 무한정 기다리는 상태

# 블로킹과 논블로킹

대부분의 어플리케이션 런타임은 동기/블로킹 모델 또는 비동기/논블로킹 모델을 따른다. 스프링 MVC는 동기/블로킹 모델이고 Node.js나 WebFlux는 비동기/논블로킹 모델이다.

# 블로킹

함수 A에서 함수 B를 호출한다고 가정하자. 함수 A 실행 도중에 함수 B를 호출했을 때 함수 B가 끝날 때까지 기다렸다가 남은 부분을 실행하는 것을 블로킹이라고 한다.

# 논블로킹

함수 A 실행 도중에 함수 B를 호출했을 때 함수 B가 끝날 때까지 기다리지 않고 자신의 실행흐름을 수행하는 것을 논블로킹이라고 한다.

# 동기와 비동기

# 동기

함수 A에서 함수 B를 호출한다고 가정하자. 함수 A 실행 도중에 함수 B를 호출했을 때 함수 B가 끝날 때까지 기다렸다가 남은 부분을 실행하면 두 함수 사이에 연관 관계가 있기 때문에 동기화되었다고 한다.

# 비동기

함수 A 실행 도중에 함수 B를 호출했을 때 함수 B가 끝날 때까지 기다리지 않고 자신의 실행흐름을 수행하기 때문에 연관 관계가 없으며, 이를 비동기라고 한다.

결국 블로킹/논블로킹, 동기/비동기는 관점의 차이이며, 일반적인 시스템은 동기/블로킹 모델비동기/논블로킹 모델로 구분된다. 비동기/논블로킹 모델에서는 일반적으로 호출하는 함수의 종료 시점을 알 수 없기 때문에 종료 시점에 실행할 코드를 콜백, 람다 형태로 전달한다. 다만 콜백이 너무 길어저 코드가 지저분해질 수도 있기에 Kotlin에서는 코루틴의 suspend함수, JavaScriptasync/await 키워드를 사용할 수 있다.

# CPU 스케줄링

  • 멀티 프로세스 환경에서는 대부분 CPU 코어 수 보다 많은 프로세스가 실행되기 때문에 이 프로세스를 병행(Concurrency)적으로 돌아가면서 실행시켜야한다. 이 전략을 CPU 스케쥴링이라고 한다.
  • 비선점형: 하나의 프로세스가 끝나기 전까지 다른 프로세스가 선점하지 못한다.
    • FIFO
    • SJF(Shortest Job First)
      • 실행 시간 추정치가 가장 작은 작업을 먼저 수행
      • 실행 시간이 긴 작업은 무기한 연장되기 때문에 에이징 기법을 사용
  • 선점형: 하나의 프로세스가 끝나지 않아도 다른 프로세스가 선점할 수 있다.
    • Round Robin
      • 일정한 시간 만큼 돌아가면서 실행
    • SRT (Shortest Remaining Time)
      • 남아있는 실행 시간의 추정치가 가장 작은 프로세스를 먼저 수행
      • 현실적으로 남아있는 실행 시간 계산이 어렵다.

# 기아 상태(Starvation)

  • 우선순위가 낮은 프로세스가 실행되지 않는 상태.
  • Aging으로 해결할 수 있다.

# 지역성

프로그램이 실행될 때 모든 영역을 골고루 참조하는게 아니라 특정 시간, 특정 공간에 집중적으로 참조한다는 특성

  • 시간 지역성: 최근 참조한 영역이 미래에도 계속 참조할 가능성이 높다.
  • 공간 지역성: 최근 참조한 지역의 근처를 계속 참조할 가능성이 높다. Cache Memory가 지역성을 응용한 대표적인 기술

# 가상 메모리

  • 주기억장치는 가격도 비싸고 크기의 한계가 있다. 이러한 한계를 극복하고 주기억장치보다 더 큰 프로그램을 실행하기 위해 보조 기억장치의 영역 일부를 주기억장치처럼 사용하는 것
  • 프로그램을 페이지라는 단위로 분할하고, 현재 실행중인 페이지만 주기억장치에 로드하여 실행한다.

# 쉘, 커널

  • 쉘(Shell):
    • 사용자의 명령어를 해석하여 커널에 전달한다.
    • bash, zsh 같이 다양한 쉘이 존재한다.
  • 커널(Kernel):
    • 운영체제의 핵심
    • CPU, 메모리, 프로세스, 입출력, 네트워크, 보안 등의 자원을 스케줄링하고 관리한다.