오퍼레이팅 시스템

[OS] 스레드

유승혁 2022. 9. 16. 10:28

1. 스레드와 멀티 스레드의 개념

 spring에서 servlet이 해주는 스레드 관리라는 것이 있었다. 그것이 무엇인지 다루어 보자. 우리가 만든 c++ 코드를 실행하면 (프로세스) main서부터 한줄 씩 내려가면서 함수 타면서 왔다리 갔다리 한다. 이건 하나의 스레드가 움직이는 걸 본 것이다. 즉, 스레드란 실행 흐름을 의미한다.

멀티 스레딩이란 바로 하나의 프로세스 위에 실행 흐름이 여러 개인 것을 의미한다. 중요한 것은 스레드끼리 자원을 공유한다는 점이다. 이는 이점이기도 하고 단점이기도 하다. 통신은 쉽지만 그만큼 동시성 문제가 발생한다.

 본격적으로 다루기 전에 다루어야 할 두 가지 키워드가 있다.

 - Concurrency: 동시 진행이라는 의미로 context switch처럼 두 개의 스레드가 interleaving 하면서 진행되는 특징을 의미한다. single core에서 진행 가능하다.

 - Parallelism: 동시 실행이라는 의미로 동시에 두개의 스레드가 실행 되고 있다는 것이다. multi core에서만 진행 가능하다.

 즉 Parallelism 하지 않은 Concurrency는 가능 하나 그 역은 성립하지 않는다.

 

2. 스레드의 등장 배경

 이런 스레드가 나오기 시작한 근본은 예를 들어 A(); 실행 후 B();라는 코드가 있는데 A()의 I/O 작업이 많이 필요하다고 해보자. A()랑 B()는 실행 순서 외에는 연관관계가 없다고 하면 무작정 A()를 기다리는 것보다는 I/O 작업 하는 동안 B()를 실행하는 것이 좋아 보인다. (이 상황은 하나의 프로세스 안에서 진행 되는 것이니 multiprogramming과 햇갈리지 마시길!) 

 다른 예시로는 servlet 처럼, client가 요청이 들어 오면 client의 요청을 죄다 따라가는 게 아닌, server가 thread를 만들어서 이를 반환 해주고 server는 다음 요청을 기다리게끔 한다. 만약 thread 대신 fork도 가능 하지만 fork는 thread에 비해 굉장히 무거운 작업이라서 응답성이 떨어질 수 밖에 없다.

 그런 의미에서 thread를 light weight (baby)process라고도 부른다.

 

3. 스레드의 장점

 - 응답성: 실행 흐름이 여러 개이다 보니, A,B 둘다 서버에서 작업을 할 게 있다면 A하고 기다림, B하고 기다림 보다 A,B 둘 다 하고 서버 응답을 기다리는 거와 같이 응답 속도가 빨라진다.

 - 생성/소통 비용: fork가 아니라서 PCB를 만들 필요도 없고 그러다 보니 스레드 switching은 process에 비해 훨씬 빨라질 수 밖에 없다. 또한 새로운 메모리를 할당 하는 것이 아니라 자원을 공유하기 때문에 communication cost가 kernel의 개입이 필요한 process 통신에 비해 비용이 굉장히 적다.

 - Multicore에 대한 확장성: 사실상 멀티 스레딩을 하는 가장 큰 이유. Parallelism인데, 하나의 프로세스에 여러 스레드를 만들어 여러 cpu에게 각각 할당을 하면 수행시간이 말도 안되게 빨라진다. 예를 들어 길찾기를 하는데 100가지 전부를 하나의 스레드가 한번씩 가보는 것보다 10개의 core가 10가지 씩 전담해서 갔다오면 수행시간이 빨라질 것이다.

 중요한 것은 길찾기는 이렇게 분배가 가능하지만, 이 세상의 task들은 분할하지 못하는 경우가 대부분이다. core가 2개 있다고 무조건 2배 빨라질 수 있는 것이 아니기 때문이다. 작업의 순서가 있을 수도 있으니. 아무튼 이러한 특징을 정리한게 암달의 법칙이다. core 개수 늘리면 얼마나 빨라질까?

speedUp <= 1/S+(1-S)/N   

S는 serial 실행 영역, N은 core의 개수를 의미한다.

 추가적으로 parallelism 이용 방식은 다음과 같다. 

  * Data parallelism: task들 사이에서 작업을 분할 한다. 미로찾기 처럼 1~100을 더해야 하는 작업을 10개의 스레드가 나누어서 한다.

  * Task parallelism: 같은 데이터에 대해 여러 작업을 해야할 때 작업을 기준으로 나눈다. 1~100을 더하는 작업, 빼기 작업, 곱하기 작업을 각 cpu에게 나눈다.

 

4. Multithread 동작 과정

 스레드를 생성할때는 최대한 얇고 빠르게 만들기 위해 user/kernel stack영역을 제외한 메모리 영역은 공유하지 않는다. 생각해보면 stack은 실행흐름에 직결 되기 때문에 당연한거 같기도. 또한 Concurrency 측면에서도 하나의 코어에서 여러 스레드를 번갈아 가며 실행 해야하기 때문에 PCB와 비슷한 TCB가 필요해 졌다. TCB에는 PC와 같은 register 정보들, 우선순위 등등 존재한다. 

 TCB는 PCB에 비해 훠얼씬 작은 단위이고 애초에 PCB안에 속해있다. 즉 multithread의 process model은 process image안에 PCB, User Address Space, {TCB, User Stack, Kernel Stack}의 여러 쌍 으로 이루어져 있다.

 스레드를 생성하면 TCB와 stack 영역만 만든다는 말은 data, heap, code 영역은 공유한다는 것이다. 당연지사 code는 변함이 없으니 그렇다 쳐도 data, 즉 전역변수를 공유해서 사용하기 때문에 동기화 작업이 무조건 필요하다.

 

5. Multithreading Models

 model은 크게 3가지가 존재한다.

 - KLT: kernel level에서 스레드가 존재하는 것이다. kernel이 모든 것을 통합 관리 한다. 즉, 이말은 thread 내에서의 switching은 kernel level의 진입이 필요하다는 의미이다. switching 에도 system call이 동작 해야하고 그러면 이전에 말한 것 처럼 user level의 정보들을 기록하고 kernel mode로 진입하고,,, mode switch가 발생한다는 것이다. 하지만 그만큼 안전하고 확실하다.

 - ULT: user-level에서 library 형태로 multithread가 제공 된다. SW가 흉내를 낸 것이다보니, kernel은 스레드가 하나만 있다고 생각한다. 그렇기에 Parallelism이 지원 되지 않는다. 뿐만 아니라 어떤 스레드가 system call을 호출하면 자연스럽게 나머지 스레드들도 block 이 되어버린다. 왜냐하면 kernel입장에서는 system call이 왔으니 ULT 전체가 kernel level로 진입했기 때문이다.

 하지만 장점은 굉장히 빠르다는 것과 kernel에 의존적이지 않아 어떠한 os에도 적용할 수 있다는 점. 그리고 정교하게 스레드를 관리 할 수 있게 된다. 그리고 생성이나 조작 동기화 과정이 mode switch가 필요하지 않아 굉장히 빠르다.

 - Combined ULT/KLT: 각 장점으로 서로의 단점을 서로 보안하기 위해 두 가지를 합쳐버렸다. kernel level에 여러 스레드를 만들고 kernel에서 나온 스레드가 user level에서 libraray 덕에 여러 스레드로 분할 된다. 아래 그림처럼.

 이렇게 되면 왼쪽의 3가닥 스레드가 실행 되다가 어떤 녀석이 system call 호출 하면 kernel level의 두 스레드 중 하나에서 실행 하고 나머지 두 가닥은 다른 스레드를 사용하는 등 ULT와 KLT를 상호보완할 수 있게 되었다!

 

 

 

 

 

 

 

 

 

 

'오퍼레이팅 시스템' 카테고리의 다른 글

[OS] DeadLocks  (1) 2022.09.20
[OS] 동기화  (2) 2022.09.19
[OS] 스케줄링  (1) 2022.09.15
[OS] 프로세스  (0) 2022.09.14
[OS] 자원 보호와 시스템 콜  (0) 2022.09.13