Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added week2/.DS_Store
Binary file not shown.
198 changes: 198 additions & 0 deletions week2/chapter3_Process/echo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
---
createdAt: 2024-01-27
updatedAt: 2024-01-27
tags:
- OS
sourceType: Book
---
프로세스: 실행 중인 프로그램 → 시스템에서 작업의 단위

# 프로세스 개념

작업, 사용자 프로그램, 또는 태스크
현대에서는 프로세스 선호

## 프로세스

비공식적으로 프로세스는 실행 중인 프로그램

프로세스의 현재 활동의 상태를 **프로그램 카운터**와 프로세서 레지스터의 내용으로 나타냄

![[Chapter 3. Process 2024-01-27 09.41.20.excalidraw]]

- Text: 실행 코드
- Data: 전역 변수
- Heap: 프로그램 실행 중에 동적으로 할당되는 메모리
- Stack: 함수를 호출할 때 임시 데이터 저장소(매개변수, 복귀 주소 및 지역 변수)


- 텍스트 및 데이터 섹션 크기는 프로그램 실행 시간 동안 크기가 변하지 않음
- 스택과 힙은 변함
- 함수가 호출될 때마다 매개변수, 지역변수 , 복귀 주소를 포함하는 **활성화 레코드**가 스택에 푸시 된다.
- *이때 운영체제는 힙과 스택이 서로의 방향으로 겹치지 않도록 해야함*

> 프로세스 != 프로그램

프로그램은 명령어 리스트를 내용으로 가진 디스크에 저장된 파일(실행 파일) - 수동적 존재

프로세스는 다음에 실행할 명령어를 지정하는 프로그램 카운터와 자원의 집합을 가짐 - 능동적 존재

예를 들어, 여러 브라우저 프로그램을 동시에 실행 시킬 수 있지만 각각 별도의 프로세스

### 프로세스 상태

프로세스는 실행되면서 **상태**가 변한다.
![[Screenshot 2024-01-27 at 10.38.56.png]]

- new: 생성
- running: 실행
- waiting: 대기(입출력 완료, 신호 수신)
- ready: 처리기에 할당되기를 기다리는 중
- terminated: 실행 종료

### 프로세스 제어 블록
![[Screenshot 2024-01-27 at 10.41.04.png]]
Process Control Block, PCB

- 상태 - 프로세스 상태
- 카운터 - 다음 실행할 명령어의 주소
- 레지스터 - 다양한 레지스터들과 상태코드, 프로그램 카운터와 함께 상태정보는 나중에 다시 스케줄 될 때 인터럽트 발생 시 저장
- 메모리 관리 정보 - OS에 의해 사용되는 메모리 시스템에 따라 기준 레지스터와 한계 레지스터의 값, 페이지 테이블, 혹은 세그먼트 테이블과 같은 정보 포함
- 회계 정보 - CPU 사용 시간, 경과 시간, 프로세스 번호 등등
- 입출력 상태 정보 - 이 프로세스에 할당된 입출력 장치들과 열린 파일 목록 등

### 스레드

프로세스 개념을 확장해 한 프로세스가 여러 실행 스레드를 가지도록 허용

## 프로세스 스케줄링

- 프로세스 스케줄러는 코어에서 실행 가능한 여러 프로세스 중에서 하나의 프로세스를 선택
- 현재 메모리에 있는 프로세스 수 = 다중 프로그래밍 정도
- 대부분의 프로세스는 I/O 바운드 혹은 CPU 바운드 프로세스

### 스케줄링 큐
- 프로세스가 시스템에 들어가면 준비 큐에 들어가 준비 상태
- 이때 큐는 연결 리스트
- 준비 큐 헤더에는 리스트의 첫 번째 PCB 포인터 저장 → 각 PCB에는 다음 PCB 포인터 필드 포함

준비 큐 외에도 다른 큐 존재
- 프로세스에 CPU 코어가 할당되면 프로세스는 실행 후 종료, 인터럽트, I/O 요청완료 등 특정 이벤트 발생까지 기다림
- 이때 프로세스가 기다리는데 이때 대기큐에 삽입
![[Screenshot 2024-01-27 at 18.13.23.png]]

![[Screenshot 2024-01-27 at 18.13.37.png]]

### CPU 스케줄링
- 역할: 준비 큐에 있는 프로세스 중 하나의 프로세스에 CPU 코어 할당
- 새 프로세스 자주 선택해야함
- 100 밀리초마다 실행
- 일부 운영체제는 스와핑 형태의 스케줄링 보유
- 메모리에서 프로세스를 제거해 다중 프로그래밍 정도 감소
- 디스크로 스왑아웃 하면서 현재 상태 저장 → 스왑인하면서 복원

### 문맥 교환

- 인터럽트 발생하면 인터럽트가 끝난 후 문맥 복구할 수 있도록 저장해야함
- 이때 문맥은 PCB에 표현
- 어떤 모드이건 CPU 현재 상태를 저장하는 작업 수행 후 상태 복구 작업 수행
- CPU를 다른 프로세스로 교환하는 작업도 문맥 교환
- 운영체제가 복잡해지면 문맥 교환 작업도 많아짐
![[Screenshot 2024-01-27 at 22.00.54.png]]

## 프로세스 연산

- OS는 프로세스 생성 종료가 가능해야함

### 생성

- 생성 프로세스 = 부모 프로세스
- 새로운 프로세스 = 자식 프로세스
- 프로세스는 트리를 형성
- PID를 통해 구별
- 주로 systemd가 PID 1 프로세스
- fork() 시스템 콜을 통해 생성
- 그 다음 exec()를 통해 메모리 공간을 새로운 프로그램으로 교체
- 자식 실행 동안 할 일 없으면 wait()

생성 방식은 2가지
1. 부모 자식 동시 실행
2. 부모는 자식이 실행이 종료할 때가지 기다리기

주소공간으로는
1. 자식 프로세스는 부모 프로세스의 복사본
2. 자식 프로세스는 자신의 새로운 프로그램을 보유

### 종료

- 프로세스가 실행을 종료하면 exit 시스템 콜 → 운영체제에게 자신의 삭제 요청
- 부모 프로세스에 wait을 통해 상태값을 반환 가능
- 이때 모든 자원이 할당 해제되고 운영체제로 반납

- 자녀 PID를 통해 종료 가능
- 부모에 할당된 자식이 자원을 초과할때
- 자식 테스크가 필요 없을때
- 부모가 종료될때 자식도 강제 종료됨 - 연쇄적 종료
- 좀비 프로세스: 부모가 wait을 호출하지 않아서 프로세스 테이블에 남아있는 상태
- 고아 프로세스: 부모 프로세스가 wait을 호출하지 않고 종료

## 프로세스간 통신 IPC


- 운영체제 내에서 프로세스는 독립적이거나 협력적
- 협력적
- 정보 공유: 정보에 병행 접근 가능
- 계산 과속화: 서브 테스크로 나누어 병렬 처리 가능
- 모듈성: 스레드 프로세스로 나누어 모듈 형태 구성

## 공유 메모리

- 통신하는 프로세스들이 공유 메모리 영역을 구축해야함
- 공유 메모리 세그먼트를 생성하는 프로세스 주소 공간에 위치
- 다른 프로세스 메모리에 접근 불가능한 OS 제약을 제거 했기 때문에 프로세스가 동일한 위치에 쓰지 않도록 해야하는 책임 주체
- 공유 메모리 구축 과정에서만 시스템콜이 사용되기 때문에 빠름

## 메세지 전달

### 방식

- 직접 / 간접
- 동시식 / 비동기식
- 자동/ 명시적 버퍼링

## 직접 통신 (명명)

- 하나의 연결이 존재해야함
- 송,수신자의 이름을 명시
- 송, 수신자 프로세스 모두 상대방 이름을 제시하는 대칭성, 하지만 비대칭 방식 변형 가능

### 간접 통신

- 메일 박스 혹은 포트로 송수신
- 프로세스가 메일 박스로 메세지를 넣고 제거하는 방식
- 고유 ID를 가짐
- 다수 메일 박스를 통해 다른 프로세스와 통신 가능
- 메일 박스는 운영체제 혹은 프로세스에 의해 생성 가능
- 소유권, 수신 특권은 시스템 콜을 통해 다른 프로세스에 전달 가능


## 동기화

- blocking send: 송신하는 프로세스는 수신자가 수신할때까지 봉쇄
- blocking receive: 메세지가 이용 가능할때까지 수신자 봉쇄
- non-blocking send: 송신하는 프로세스가 메세지 보내고 작업 이어서
- non-blocking receive: 수신하는 프로세스가 null 수신 가능

### 버퍼링

- 통신하는 프로세스들에 의해 교환되는 메세지는 임시 큐에 들어감
- 큐 구현 방식
1. 무용량 큐: 큐 최대 길이 0, 메세지 가질 수 없음
2. 유한 용량: n개의 메세지 수용
3. 무한 용량: 무한 길이 가능

- 대기발생
1. 송신자는 메세지 수신까지 대기
2. 공간이 생길때까지 큐 봉쇄
3. 없음

157 changes: 157 additions & 0 deletions week2/chapter4_Threads&Concurrency/echo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
---
createdAt: 2024-01-27
updatedAt: 2024-01-27
tags:
- OS
sourceType: Book
---
# 스레드와 동시성

- 스레드는 CPU 이용의 기본 단위
- ID, PC, 레지스터 집합, 스택으로 이루어짐
- 같은 프로세스의 스레드끼리 운영체제 자원 공유

## 동기

- 기존 프로세스와 새로 생성한 프로세스가 해야할 일이 같다면 만드는 것보다 스레드를 만드는게 효율적이라서
## 다중 스레드 장점

- 응답성: 프로그램의 긴 작업 수행 및 봉쇄에도 프로그램 수행이 계속 되기 때문에 응답성 증가
- 자원 공유: 프로세스는 별도의 전달 방식이 필요하지만 스레드는 자동 공유
- 경제성: 스레드간 문맥 교환이 빠르고 생성 비용이 적다.
- 규모 적응성: 다중 처리 구조에서 스레드는 병렬로 처리 가능
# 다중 코어 프로그래밍

- 여러 CPU 사용
- 동시 시스템: 모든 작업이 진행되게 해 둘 이상의 작업 지원(시분할 시스템)
- 병렬 시스템: 실제로 둘 이상의 작업 동시 수행

## 도전과제
- 테스크 인식: 동시 처리 가능한 테스크로 나눌 수 있는 영역 찾기
- 균형: 각 작업이 균등하도록 테스크 나누기
- 데이터 분리: 데이터도 독립적으로 관리
- 데이터 종속성: 둘 이상의 테스크가 의존하지 않도록
- 시험 및 디버깅: 다양한 실행 경로에서 테스트 디버깅 시행

## 병렬 실행 유형

1. 데이터 병렬 실행: 동일한 데이터 부분 집합을 다수 코어에 분배해 연산
2. 테스크 병렬 실행: 테스크를 다수 코어에 분배해 연산을 실행
![[Screenshot 2024-01-27 at 22.57.17.png]]


## 다중 스레드 모델

- 스레드는 사용자 스레드와 커널 스레드로 나누어짐
- 사용자 스레드: 커널 위에서 지원, 커널 지원 없이 관리
- 커널 스레드: OS 직접 지원

## 다대일

- 커널 스레드 1: 사용자 스레드 N
- 관리: 사용자 공간의 스레드 라이브러리
- 단점:
- 한 스레드가 봉쇄형 시스템 콜을 할 경우 전체 프로세스 봉쇄
- 한 번에 하나의 스레드만이 커널에 접근 → 멀티 코어에서 병렬 실행 X
- 그린 스레드가 이 방식 사용

## 일대일

- 커널 1: 사용자 1
- 하나의 스레드가 봉쇄적 시스템 콜을 해도 다른 스레드 실행
- 단점:
- 커널 스레드를 생성해야해서 시스템 성능 부담

## 다대다

- 커널 N: 사용자 M (N >= M)
- two-level model 사용
- 동시에 1:1도 지원

# 스레드 라이브러리

프로그래머에게 스레드 생성 관리하기 위한 API 제공

- 사용자 공간 라이브러리: 시스템 콜이 아닌 사용자 공간에서 지역 함수 호출
- 커널 수준 라이브러리: 커널 시스템 콜

생성법
- 비동기 스레딩
- 부모가 자식 스레드 생성 후 부모 실행 재개, 자식과 독립적으로 실행, 데이터 공유 거의 없음
- 동기 스레딩
- 자식 스레드가 종료되면 부모 스레드 실행, 데이터 공유할 수 있다.

# 암묵적 스레딩

- 스레딩 생성 관리 책임을 컴파일러나 런타임 라이브러리가 가져감

## 스레드풀

- 스레드를 미리 만들어 스레드 풀로 만듬
- 프로세스 시작시 일정 수 스레드로 풀 만들어 둠

- 순서
- 유휴 스레드
- 요청 들어오면 깨어남
- 유휴 스레드가 없으면 생길때까지 대기

- 풀 개수는 코어수, 물리 메모리 용량, 요청 최대 개수 등으로 계산

## Fork Join

- 부모 스레드가 자식 스레드 생성한 다음 자식의 종료를 기다리고 join
- 결과 확인하고 결합 가능
- 동기 버전의 스레드 풀 방식

# 관련 문제들

## Fork Exec 시스템 콜

- 다중 스레드에서 프로세스를 생성하는 fork()를 호출할때
- 새로운 프로세스는 한 개의 스레드만 가지는 프로세스?
- 아니면 모든 스레드를 복사한 프로세스?
- 몇몇 OS는 둘 다 제공
- 만약 exec를 호출한다면 모든 스레드 복제는 불필요
- exec 호출하지 않는다면 모든 스레드 복제 필요

## 신호 처리

- 어떤 이벤트가 일어났다는 것을 알려주기 위해 사용
- 동기적 혹은 비동기적으로 전달
- 어쨋든 처리해야함
- 신호는 특정 이벤트가 일어나야 생성
- 생성된 신호가 프로세스에 전달
- 신호가 전달되면 반드시 처리

- 둘 처리기 중 하나에 의해 처리
- 디폴트
- 사용자 정의
- 신호 전달 방식
- 신호가 적용될 스레드에게 전달
- 모든 스레드에게 전달
- 몇몇 스레드들에만 선택적으로 전달
- 특정 스레드가 모든 신호를 전달받도록 지정

### 스레드 취소

취소해야할 스레드 = 목적 스레드

- 비동기식 취소: 한 스레드가 즉시 목적 스레드 종료
- 지연 취소: 목적 스레드가 주기적으로 자기 자신이 종료 되야하는지 점검
### 스레드 로컬장치 TLS

- 스레드들은 프로세스 데이터 공유하는데 자기만 엑세스 할 수 있는 데이터 필요
- 이를 TLS
- 정적 데이터와 유사
- 다만 스레드마다 고유

### 스케줄러 엑티베이션

- 다대다 또는 two - level model을 구현하는 시스템은 중간 자료 구조를 둠
- 이를 경량 프로세스 혹은 LWP라고 부름
- 하나의 커널 스레드에 부속되어있음
- 스케줄 하는 대상은 해당 커널 스레드
- 해당 커널 스레드 봉쇄 → 해당 커널 스레드의 LWP 봉쇄 → 해당 LWP에 부속된 사용자 스레드 봉쇄

- 사용자 스레드 라이브러리와 커널 스레드 통신 방법의 하나는 스케줄러 엑티베이션
- 커널이 응용 프로그램에게 특정 이벤트를 알려주며 이를 upcall이라고 함