---
# System prepended metadata

title: Day10-학습정리
tags: [2020 Boostcamp]

---

###### tags: `2020 Boostcamp`
# Day10-학습정리

### 스스로 확인할 사항

- **멀티 스레드 스케줄링 방식에 대해 학습하고 정리한다.**

  - 프로세스 스케줄링과 정책은 동일함
  - `Preemtive vs Non-Preemtive`
    - Preemtive(선점 방식): 실행중인 스레드가 강제적으로 실행권을 빼앗김
    - Non-Preemtive(비선점 방식): 실행중인 스레드가 자발적으로 실행권을 내려놓음
  - `선입 선처리 스케줄링(FCFS)`
    - Ready queue에 등록된 순서 그대로 스레드를 처리
    - 실행중인 스레드가 다른 스레드에 의해 선점될 수 없음
  - `순환 처리 스케줄링(RR: Round-Robin)`
    - 스레드에 할당 시간을 부여하여 실행 시간을 제한함
    - 시분할 시스탬을 위해 개발된 선점 방식의 스케줄링
  - `우선순위 큐 스케줄링`
    - 스레드에 우선순위를 부여하고 높은 우선순위를 가진 스레드부터 실행
    - 우선순위가 같을 때 CPU의 할당 시간을 나눔
    - 선점 방식 스케줄링

- **각자 운영체제 스레드 동작 방식과 본인이 작성한 스레드 스케줄링 방식을 비교한다.**

  - Mac OS 는 priority 기반 스레드 스케줄링 알고리즘을 사용
  - 스레드가 높은 우선순위를 가졌다고 해서 특정한 실행 시간을 보장받는 것은 아님
  - 스레드의 우선순위를 높히면 다른 스레드에서 starvation이 발생할 확률 높으므로 default로 유지하는게 좋음
  - 미션때 작성한 스케줄링은 RR이고 priorty가 없음

- **스레드를 무제한으로 만들수 없다면, 프로세스가 많아질 때 성능 향상을 할 수 있는 방법이 무엇일까?**

  - 프로세스간 shared data 최소화
  - I/O 작업을 최소화 하거나, 해당 작업만을 위한 프로세스를 분리
  - CPU Bursttime을 정확하게 측정할 수 없지만, 개략적인 카테고리를 나눠 합리적인 우선순위를 부여

- **DispatchQueue 동작 방식에 대해 학습하고 정리한다.**

  > * Swift에서 Thread 관련 작업은 `Grand Central Dispatch API (GCD)`를 통해 처리
  > * Closure로 표현된 작업을 큐에 태우고, 해당 큐를 특정 Thread에 출격시켜 실행하는 방식
  > * GCD를 이용해서 multi-threading 작업을 할때는 적절한 Queue와 QoS를 골라야 함
  > * GCD는 Thread safe한 Dispatch Queue를 제공함

  - `Dispatch Queue`
    1. Main(Serial)
       * Main thread 에서 처리되는 serial queue
    2. Global(Concurrent)
       * 전체 시스템에 공유되는 concurrent queue
       * 작업 우선순위를 사전에 정의한 QoS를 활용함
    ![](https://i.imgur.com/ghTEoso.png)

  - `Quality of Service (QoS)`
    1. userInteractive
       * 중요도가 높고 즉각적인 반응이 요구되는 작업을 위해 가장 자원을 많이 쓰도록 함
       * global queue 항목이지만 main thread에서 실행됨
       * UI update, Event handling 등
    2. userInitiated
       * userInteractive 보다는 중요도가 떨어지지만 유저가 빠른 결과를 기대할 때 사용
       * 유저가 실행시킨 작업으로 Async하게 처리해야 할 일들에 사용
    3. utility
       * 시간이 다소 오래 걸리는 작업을 처리
       * 유저에게 처리가 진행되는 모습을 보일 수도 있음
       * 계산, I/O, 네트워킹, 데이터 피드 등
    4. background
       * 유저가 인지하지 못하도록 뒷단에서 실행되는 작업
       * 유저 인터렉션이 불필요하고 급하지 않은 작업

### 다같이 확인할 사항

- **플랫폼에서 정확도 높은 타이머Timer를 구현하기 위한 여러 방식에 대해 학습한다.**

  - `Timer`와 `DispatchSourceTimer` 보다 `mach_absolute_time` 을 사용해 구현하는 것이 정확함

- **멀티 스레드가 공용 리소스에 접근할 때 임계구역을 다루는 방식(Semaphore, Mutex 등)에 대해 학습하고, 어떤 경우에 사용해야 하는지 토론한다.**

  - `Semaphore`

    - 정수값을 가지는 변수라 볼 수 있음
    - `semWait`: 세마포어 값을 감소시킴. 값이 음수가 되면 `semWait`를 호출한 프로세스는 블록 됨
    - `semSignal`: 세마포어 값을 증가시킴. 값이 양수가 아니면(0이거나 음수면), semWait 연산에 의해 블록된 프로세스들을 깨움

    ```c++
    struct semaphore {
    	int count;
        	queueType queue;
    };
    
    void semWait (semaphore s) {
    	s.count--;
        if (s.count < 0) {
        	/* 이 구역으로 들어왔다는 것은 현재 프로세스(혹은 쓰레드)가 공유 자원에 접근할 수 없다는 것을 의미*/
        	/* 요청한 프로세스를 s.queue에 연결 */
            /* 요청한 프로세스를 블록 상태로 전이 시킴*/
        }
    } 
    
    void semSignal (semaphore s) {
    	s.count++;
        if (s.count <= 0) {
        	/* count가 0보다 작거나 같다는 것은 대기하고 있는 프로세스(또는 스레드)가 존재한다는 것을 의미*/
            /* s.queue에 연결되어 있는 프로세스를 큐에서 제거 */
            /* 프로세스의 상태를 실행 가능으로 전이시키고 ready list에 연결 */
        }
    }
    ```

    - Swift의 세마포어: GCD Dispatch에서 제공

    ```swift
    let semaphore = DispatchSemaphore(value: 3)
    for i in 1...10 {
    DispatchQueue.global().async {
        semaphore.wait()
        defer { semaphore.signal() }
        
        // 이미지 다운로드에 3초가 걸린다고 가정
        print("Downloading image \(i)")
        Thread.sleep(forTimeInterval: 3)
        print("Image \(i) downloaded")
    }
    ```

  * `Mutex`

    * 이진 세마포어와 같이 초기값을 1과 0으로 가짐
    * 임계영역에 들어갈 때 `락(lock)`을 걸어 다른 프로세스(혹은 쓰레드)가 접근하지 못하도록 함
    *  임계영역에서 나와 해당 락을 `해제(unlock`)  

    ```c++
    mutex = 1;
    
    void lock () {
    	while (mutex != 1) {
        	/* mutex 값이 1이 될 때까지 기다립니다.*/
        }
        /* 이 구역에 도착했다는 것은 mutex 값이 1이라는 것을 의미.
           따라서 이제 뮤텍스 값을 0으로 만들어 다른 프로세스(혹은 쓰레드)가 접근하지 못하도록 막아야 함.
        */
        mutex = 0;
    }
    
    void unlock() {
    	/* 임계 구역에서 나온 프로세스는 다른 프로세스가 접근할 수 있도록 락을 해제.*/
    	mutex = 1;
    }
    ```

  ✅ 공유된 자원의 데이터를 여러 프로세스가 접근하는 것을 막을 때: 세마포어

  ✅ 공유된 자원의 데이터를 여러 쓰레드가 접근하는 것을 막을 때: 뮤텍스

  