# 운영체제 관련 질문

## 목차
- [Q. 프로세스(Process)와 쓰레드(Thread)](#q-프로세스process와-쓰레드thread)
- [Q. 프로세스 동기화](#q-프로세스-동기화)
- [Q. 교착상태(DeadLock, 데드락)](#q-교착상태deadlock-데드락)
- [Q. CPU 스케줄링](#q-cpu-스케줄링)
- [Q. 페이징](#q-페이징)
- [Q. 가상 메모리](#q-가상-메모리)
- [Q. 캐시 메모리(Cache Memory)](#q-캐시-메모리cache-memory)


## Q. 프로세스(Process)와 쓰레드(Thread)
### 1. 프로세스
프로세스는 디스크에 있는 프로그램을 메인 메모리에 적재하여 실행되고 있는 상태를 말합니다. 프로그램이 실행한다는 것은 운영체제로부터 Code, Data, Stack, Heap 영역의 메모리를 할당받고, CPU와 I/O 등 연산을 수행할 수 있는 상태를 말합니다. 프로세스는 각각의 메모리를 독립적으로 할당받기 때문에 서로 다른 프로세스와 통신하려면 비용이 큽니다. 그리고 쓰레드를 1개 이상을 갖고 있습니다.

#### PCB(Process Control Block)
PCB는 프로세스의 모든 정보를 담고 있는 운영체제의 자료구조입니다. 운영체제는 프로세스를 관리하기 위해 프로세스의 생성과 동시에 고유한 PCB 를 생성합니다. CPU는 하나의 프로세스만 실행하는 것이 아닌 여러 프로세스를 번갈아가면서 실행합니다. 이를 할 수 있는 이유는 운영체제에서 각각의 프로세스 상태를 PCB로 가지고 있기 때문입니다. 

PCB에 저장되어 있는 정보는 다음과 같습니다.
- **프로세스 식별자(Process ID, PID)** : 프로세스 식별번호
- **프로세스 상태** : new, ready, running, waiting, terminated 등의 상태를 저장
- **프로그램 카운터(Program Counter, PC)** : 프로세스가 다음에 실행할 명령어의 주소
- **CPU 레지스터 및 일반 레지스터**
- **CPU 스케쥴링 정보** : 프로세스의 우선순위, 스케줄 큐에 대한 포인터 등
- **메모리 관리 정보** : 프로세스의 주소 공간, 페이지 테이블 또는 세그먼트 테이블 정보 등
- **입출력 상태 정보** : 프로세스에 할당된 입출력 장치들과 열린 파일 목록
- **어카운팅 정보** : 사용된 CPU 시간, 시간제한, 계정번호 등

### 2. 쓰레드
쓰레드는 프로세스의 실행 단위입니다. 프로세스 내부의 Stack을 제외한 메모리 공간을 공유하기 때문에 한 프로세스에 여러 쓰레드가 있다면 쓰레드 사이에 자원을 공유하는데 비용은 크지 않습니다. 하지만 여러 쓰레드가 한 자원을 공유할 때는 동기화를 해주어야 하므로 이에 대한 비용이 발생할 수 있습니다. 쓰레드는 독립된 실행을 위한 쓰레드 ID, PC, 레지스터, 스택으로 이루어져 있습니다.

#### Stack 영역을 쓰레드마다 독립적으로 할당하는 이유
프로그램을 실행한다는 것은 함수를 실행한다는 것과 같습니다. 함수 호출시 전달하는 인자, 함수가 끝나고 되돌아갈 위치, 함수 내에 선언하는 변수 등을 저장하는 영역이 Stack 메모리 영역입니다. 즉 함수를 실행하는데 필요한 정보를 담는 곳이 Stack 영역이므로, 독립적으로 함수를 실행하기 위해서는 최소한 Stack 영역이 필요합니다.

#### PC를 쓰레드마다 독립적으로 할당하는 이유
프로그램 카운터는 현재 쓰레드가 어디까지 진행되었는지 알 수 있는 정보입니다. CPU는 여러 쓰레드를 번갈아가면서 실행하는데, 실행중인 한 쓰레드가 중단되었다가 다시 이어서 실행하기 위해서는 그 전에 어디까지 수행했는지에 대한 정보인 PC가 필요합니다.

### 3. Context Switching(문맥 교환)
문맥 교환은 CPU에서 프로세스나 쓰레드를 번갈아 수행하는 것을 말합니다. 운영체제는 하드웨어 자원을 효율적으로 사용하기 위해 메인 메모리에 여러 프로세스나 쓰레드 단위를 적재한 후 CPU가 이를 번갈아 실행하도록 합니다. 이 때 CPU가 한 프로세스를 수행중인 것을 멈추고 다른 프로세스를 실행하는 것을 문맥 교환이라고 말합니다.

#### Context Switching Overhead
문맥 교환을 할 때마다 현재 프로세스(쓰레드) 상태를 저장하고, 다음 실행할 프로세스 상태를 가져오는 작업을 해야합니다. 이 때 발생하는 비용을 Context Switching Overhead라고 합니다.

![문맥 교환 과정](./images/context_switching.png)

위는 프로세스 P0에서 P1으로 문맥 교환이 발생하는 그림입니다. 여기서 P1의 idle 상태가 Context Switching Overhead입니다. 이 순간에는 CPU가 어떠한 일도 할 수 없기 때문에 매우 비효율적인 작업입니다.

문맥 교환은 프로세스 단위나 쓰레드 단위로 할 수 있는데, 프로세스가 쓰레드보다 가지고 있는 정보량이 많으므로 Context Switching Overhead도 큽니다.

### 4. Multi Process VS Multi Thread
멀티 프로세스는 여러 프로세스를 동시에 수행하는 환경이고, 멀티 스레드는 여러 스레드를 동시에 수행하는 환경입니다.

멀티 프로세스는 서로 독립적이기 때문에 데이터 통신하는 비용이 크고, 저장하고 있는 정보가 많아 context switching에 오랜 시간이 소요됩니다. 하지만 서로 독립적이므로 한 프로세스의 오류가 다른 프로세스에 영향을 주지 않아 안정적입니다.

멀티 스레드는 한 프로세스 내에서 Stack을 제외한 다른 메모리 영역을 공유하므로 자원에 대한 동기화 작업을 해야합니다. 그리고 한 스레드의 오류가 다른 스레드에 영향을 미칠 수 있습니다. 하지만 공유하고 있는 자원이 있으므로 스레드 사이에 통신이 간단하고, context switching에서 멀티 프로세스와 달리 가지고 있는 정보가 적고 캐시 메모리를 비우는 작업이 없어 더 빠릅니다.

멀티 스레드와 멀티 프로세스는 각각의 장단점이 있으므로, 정답은 없습니다. 시스템에 따라 적절하게 선택해서 사용해야합니다.


## Q. 프로세스 동기화
### 임계 영역(Critical Section)
여러 프로세스 또는 쓰레드를 사용하는 환경에서 각각의 프로세스 또는 쓰레드가 하나의 공유하는 데이터(변수, 테이블, 파일 등)를 변경하는 영역을 말합니다.

임계 영역의 대표적인 문제는 Race Condition이 있습니다. Race Condition은 하나의 공유되는 데이터에 여러 프로세스가 접근하여 값을 변경하려 할 때 그 시점이나 순서에 의해 데이터의 일관성을 깨지는 현상을 말합니다.

이러한 임게 영역 문제를 해결하기 위해서는 3 가지 조건을 만족해야합니다.
- **Mutual exclusion(상호배타)**: 오직 한 쓰레드만이 진입 가능하다. 한 쓰레드가 임계구역에서 수행 중인 상태에서는 다른 쓰레드는 절대 이 구역에 접근할 수 없다.
- **Progress(진행)**: 한 임계구역에 접근하는 쓰레드를 결정하는 것은 유한 시간 이내에 이루어져야한다.
- **Bounded waiting(유한대기)**: 임계구역으로 진입하기 위해 대기하는 모든 쓰레드는 유한 시간 이내에 해당 임계구역으로 진입할 수 있어야 한다.

#### 임계 영역 해결 방법
- Semaphore(세마포)
    - 소프트웨어 동기화 도구
    - Mutual exclusion 문제를 해결하고, 프로세스 진입 순서를 조절할 수 있다.
    - 카운팅의 값에 따라 진입할 수 있는 프로세스 개수를 늘릴 수 있다.(한 개 이상을 접근하게 할 수 있음)
    - 한 프로세스가 진입하면 `acquire()`을 호출하고 그 후 다른 프로세스가 진입하려하면 큐에 넣어 block 한다. 진입했던 프로세스가 작업을 끝내면 `release()`를 호출하며, 큐에 block되어 있는 프로세스를 깨워 진입하는 형식으로 동작한다.(busy waiting 문제 해결)
        - busy waiting은 프로세스가 접근할 수 있는지 확인하는 무한 반복문을 말한다. 
- 모니터
    - 고급 언어의 설계 구조물로서, 개발자의 코드를 상호배제 하게끔 만든 추상화된 데이터 형태이다.
    - 세마포와 달리 직접적인 접근 처리를 할 필요가 없다.
    - 대표적으로 자바의 `synchronized` 키워드가 있다.


## Q. 교착상태(DeadLock, 데드락)
프로세스는 실행을 위해 CPU, 메모리 등과 같은 공유된 자원이 필요합니다. 여러 프로세스가 이러한 공유된 자원에 접근하는데 만약 순서가 잘못되어 모든 프로세스가 자원을 기다리는 상태 즉 멈춰버리는 상태가 될 수 있습니다. 이를 교착상태라고 합니다.

### 교착상태 필요 조건
교착상태가 발생하는 필요 조건은 4 가지가 있습니다. 문자 그대로 필요 조건이기 때문에 4 가지가 모두 만족한다고 해서 반드시 발생하는 것은 아닙니다.
- **Mutual exclusion(상호배타)**: 한 프로세스가 자원을 사용하고 있다면, 다른 프로세스는 이 자원을 사용할 수 없다.
- **Hold and wait(보유 및 대기)**: 한 프로세스가 자원을 가지고 있는 상태에서 대기한다.
- **No Preemption(비선점)**: 한 프로세스가 자원을 수행하는 중에는 다른 프로세스가 중간에 끼어들 수 없다.
- **Circular wait(환형대기)**: 프로세스가 요구하는 자원의 방향이 원형을 이룬다.

### 교착상태 처리
- **교착상태 방지(Deadlock Prevention)**: 교착상태 방지는 교착상태가 발생하기 위한 4 가지 필요 조건 중 최소 한 가지 이상을 만족시키지 않도록 하는 것이다.
- **교착상태 회피 (Deadlock Avoidance)**: 교착상태 회피는 교착상태가 자원 할당에 대한 잘못된 승인으로 보는 관점이다. 따라서 자원이 할당 되었을 때 교착상태가 발생하지 않는지 미리 판단한 후에 할당을 해준다. (Ex, Banker's Algorithm)
- **교착상태 검출 및 복구 (Deadlock Detection & Recovery)**: 교착상태를 미리 방지하는 것이 아닌 교착상태가 발생했을 때 이를 확인하고 복구하는 작업을 한다. 교착상태가 일어났는지 주기적으로 검사해주어야 하고, 복구하기 위해 메모리 상태를 주기적으로 검사해야 하는 오버헤드가 발생한다.
- **교착상태 무시**: 교착상태를 처리하는 것에 너무 많은 비용이 들 때는 무시하는 방법도 있다.


## Q. CPU 스케줄링
- [[운영체제(OS)] 6. CPU 스케줄링](https://velog.io/@codemcd/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9COS-6.-CPU-%EC%8A%A4%EC%BC%80%EC%A4%84%EB%A7%81)


## Q. 페이징
- [[운영체제(OS)] 13. 페이징](https://velog.io/@codemcd/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9COS-13.-%ED%8E%98%EC%9D%B4%EC%A7%95)


## Q. 가상 메모리
- [[운영체제(OS)] 15. 가상메모리](https://velog.io/@codemcd/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9COS-15.-%EA%B0%80%EC%83%81%EB%A9%94%EB%AA%A8%EB%A6%AC)


## Q. 캐시 메모리(Cache Memory)
캐시 메모리는 속도가 빠른 장치와 느린 장치의 병목 현상을 줄이기 위한 메모리를 말합니다. 예를 들면 다음과 같습니다.
- CPU와 메모리 사이의 병목 현상 완화
- 웹 브라우저 캐시, 웹 서버와 로컬 사이의 병목 현상 완화
- 인 메모리 데이터베이스(레디스), 메모리와 하드디스크 데이터베이스 사이의 병목 현상 완화
- ...

캐시는 CPU와 메모리로 예를 들면 CPU는 먼저 캐시 메모리에 접근하여 필요한 자원이 있는지 확인한 후 없다면 메모리까지 이동하여 자원을 찾아서 가져옵니다. 이와 같이 캐시 메모리에 필요한 자원이 없는 것을 캐시 미스(cache miss), 있는 것은 캐시 힛(cache hit)이라고 합니다.

따라서 캐시의 적중률(Hit Rate)이 중요합니다. 캐시의 적중률을 극대화하기 위해 지역성(Locality)의 원리를 사용합니다. 지역성은 아래와 같이 두 가지로 나뉩니다.
- **시간 지역성(Temporal Locality)**: 최근 참조된 데이터를 다시 참조하는 특성
- **공간 지역성(Spatial Locality)**: 참조된 데이터와 인접한 데이터를 참조하는 특성

프로그램 특성상 시간 지역성(for, while 문과 같은 반복문)과 공간 지역성(배열, 절차적인 코드 처리)을 충분히 따르고 있기 때문에 캐시의 적중률은 매우 높은 편입니다. 따라서 많은 분야에서 캐시를 사용하고 있습니다.