버티의 블로그
[운영체제 #04] Threads 본문
Thread는 CPU 실행의 기본 단위로, 동일 프로세스 내에서 여러 스레드가 동시에 실행되며 멀티 태스킹을 가능하게 한다. 보통 스레드는 스레드 ID, PC, 레지스터, 스택으로 구성된다.
멀티 스레드 환경은 한 프로세스 내 여러 스레드들이 존재하는 것으로, 이들은 code, data, files(text)를 공유하지만 registers, stack, PC는 각각 다르다. 메모리를 적게 차지하고, CPU 시간을 최소화(light weight) 하기 위해 멀티 스레드를 사용한다. 이렇게 함으로써 얻는 이득은 다음과 같다.
- Responsiveness : 한 스레드에 문제가 생겨도 프로그램 실행을 허락함으로써 사용자에 대한 응답성이 증가한다.
- Resource Sharing : 프로세스의 Shared memory, Message passing 공유 방식보다 더 쉽게 리소스 공유가 가능하다.
- Economy : 프로세스 단위의 문맥교환보다 스레드 단위 교환이 더 저렴하다.
보통 서버에는 main thread와 worker thread가 존재하고 이들이 client request를 처리하는 구조이다. main thread는 request(1)에 맞는 worker 스레드를 만들어 작업시키고(2), 다른 Request가 올때까지 대기한다(3). 이는 마치 은행에서 창구 안내원의 역할이다. 창구 안내원이 실제 은행 업무를 하지 않고 안내만 하는 느낌이다. worker thread는 실제 작업을 하는 스레드들을 지칭한다. 보통 서버와 연결된 client 하나당 worker thread 하나가 대응된다.
Multicore Programming
- Concurrency : 하나의 코어에서 여러 작업을 빠르게 전환하며 수행하여 마치 동시에 실행되게끔 보이는 것이다.
- Parallelism : 여러 코어에서 여러 작업을 병렬적으로 동시에 수행하는 것이다.
다중 코어 시스템에서는 시스템이 각각의 스레드들을 각 코어에 배치할 수 있기 때문에, 스레드들이 위와 같이 병렬적으로 실행된다. 기존 단일 코어 시스템은 Concurrency는 만족하지만 parallelism을 만족하지 못했는데, 다중 코어 시스템은 여러 task를 동시에 진행할 수 있으면서 기존의 concurrency도 만족할 수 있다.
일반적으로 병렬 실행은 아래와 같이 2가지 유형이 존재한다.
- Data (Level) Parallelism : 각 스레드들이 동일한 데이터의 subset을 분배받아 동일한 연산을 수행하는 유형이다.
- Task Parallelism : 각 스레드들이 서로 다른 작업을 수행하는 유형이다.
암달의 법칙은 병렬 처리로 얻는 성능 향상 효과의 한계를 설명하는 개념으로 위 그래프처럼 코어(스레드) 수를 늘려도 이상적인 speed up과 다르게 점점 로그함수 형태로 천천히 증가하는 것을 볼 수 있다. 따라서 최적의 코어 수를 결정하는 것이 중요하다 볼 수 있다.
- Speed up : 병렬 처리를 통한 성능 향상 비율
- S : 병렬화가 불가능한(serial) 부분의 비율
- (1-S) : 병렬화가 가능한(parallel) 부분의 비율
- N : 병렬 유닛 수
플린 분류는 마이클 플린이 제안한 컴퓨터 아키텍쳐 분류 체계인데, 컴퓨터가 명령어와 데이터를 어떻게 처리하냐에 따라 4가지로 나뉜다.
- SISD : 한 명령어가 하나의 데이터 세트에만 작업을 수행
- SIMD : 한 명령어가 동시에 여러 데이터 세트에 작업을 수행
- MISD : 여러 명령어가 동시에 하나의 데이터 세트에만 작업을 수행
- MIMD : 여러 명령어가 동시에 여러 데이터 세트에 작업을 수행
Implicit Threading
사실 지금까지 보았던 멀티 스레드 환경도 문제가 있다. clinet가 추가될때마다 새로운 스레드를 생성하고 죽이는 과정 자체에 오랜 시간이 걸릴 뿐더러, 스레드 수의 제한이 없기 때문에 client가 급격하게 많아지면 리소스 고갈이나 서버 과부하가 올 수 있다. 이러한 문제점을 해결하기 위해 스레드의 생성과 관리 책임을 컴파일러와 run-time 라이브러리에게 넘겨주는 암묵적 스레딩(Implicit Threading)이 등장했고, 대표적인 방식으로 Thread Pool이 있다.
Thread Pool의 아이디어는 프로세스가 시작하자마자 일정 수의 스레드를 미리 만들어놓는 것이다. 이후 client로부터 request가 들어오면 만들어 놓은 스레드를 깨우고(active), request를 완료하면 스레드를 다시 재우는(inactive) 방법을 사용한다. 이렇게 함으로써 얻는 이점들이 상당한데,
- 스레드를 바로바로 새롭게 만드는 방식보다 종종 더 빠르다.
- 스레드 수를 한정하여 만들기 때문에 과부화가 올 확률이 적다.
- 스레드 생성을 메인 스레드로부터 분리하기 때문에 task의 실행을 유연하게 할 수 있다.
이제 그림으로 2가지를 비교하며 흐름을 비교해보자면 다음과 같다.
멀티 스레드 환경 (Multi-Threaded server architecture)
- 메인 스레드가 request를 받으면 request struct를 만들고 새로운 worker thread를 만들어 전달한다.
- 생성된 worker thread들은 자신의 request를 처리한다.
- 처리를 완료하면 response를 client에게 전송하고 request struct 삭제 후에 worker thread는 종료된다.
스레드 풀 (Thread Pool)
- client와 통신하기 전 미리 한정된 수만큼 스레드를 만들어 놓는다.
- 메인 스레드가 request를 받으면 request struct를 만들고 request list에 추가한다.
- 스레드 풀의 worker thread가 request list에서 다음 request struct를 가져와 request를 처리한다.
- 처리를 완료하면 response를 client에게 전송하고 request struct를 삭제 후 다음 request를 처리하거나 list가 비어있으면 대기한다.
'OS_NW > 운영체제' 카테고리의 다른 글
[운영체제 #06] I/O Systems (0) | 2024.04.19 |
---|---|
[운영체제 #05] Computer System Operation (0) | 2024.04.18 |
[운영체제 #03] Interprocess Communication (0) | 2024.04.09 |
[운영체제 #02] Processes (2) | 2024.04.04 |
[운영체제 #01] Operating System Structures (0) | 2024.04.02 |