티스토리 뷰

프로그래밍/OS

Multi Thread Programming

국윤창 2018. 1. 29. 11:24

1. 개요

Thread는 CPU 이용의 기본 단위이다. thread는 ID, program counter, set of registers, stack으로 구성된다. thread는 한 process 안에 여러개 존재할 수 있으며, 같은 process에 존재하는 다른 thread들과 OS의 자원을 공유한다. 아래 그림 1은 single thread process와 multi thread process의 차이를 보여준다.

Single-threaded, multithreaded processes[그림 1] single-threaded, multithreaded processes


위 그림과 같이 thread들은 code, file, data 등을 공유하지만 register와 stack은 각각 가지고 있다. 


1.1 Motivation

Process는 여러 개의 독립된 작업들이 필요할 때 thread가 필요하다. 그림 1에서 봤듯이 thread는 여러 자원을 공유함으로써 process보다 덩치가 작다. 만약 웹서버가 여러 사용자들의 작업을 처리하기 위해 process를 매번 생성한다면 시간과 자원을 많이 소비할 것이다. multithread로 구성된 서버 구조가 아래 그림 2에 나와있다.

Multithreaded server architecture[그림 2] 다중 스레드화 된 서버 구조


1.2 Benefits

multithreading로 프로그래밍하는 이점은 크게 4개로 나눌 수 있다.

      • Responsiveness: 프로그램이 계산 집중적인 작업을 해도 프로그램의 실행이 계속되는 것을 허용함으로써 사용자에 대한 응답성을 증가시킨다. 예를 들면 한 thread가 파일을 로드하고 있는 동안 다른 thread에서 사용자와 상호작용이 가능하다.

      • Resource sharing: multi process는 process끼리 공유 메모리나 메시지 전달 기법을 통해 자원을 공유할 수 있다. 하지만 multi thread는 같은 process 내 자원을 공유한다. 후에 배우겠지만 thread들 끼리 같은 자원에 동시에 접근할 경우 문제가 생길 수 있다.

      • Economy: Process를 여러 개 만드는 것 보다 thread를 여러 개 만드는 것이 시간과 자원에서 절약된다. 그리고 Context Switching 시 thread가 process보다 빨리 된다.

      • Scalability: multithread로 구성된 프로그램은 multi core 구조에서 core 하나 당 thread 하나 씩 할당되어 병렬로 처리된다. single-thread로 구성된 process는 multi core라 하더라도 하나의 core에서만 실행된다. (물론 여러 개의 single-threaded process는 여러 개의 core에서 병렬로 실행된다.)

1.3 Multi-core Programming

최근 CPU의 경향은 칩 하나에 여러 개의 코어를 넣는 것이다. 운영체제 입장에서는 각 코어가 독립된 처리기로 보인다. multi-core programming은 multi core를 더 효율적으로 사용하고 병행성을 향상시킬 수 있는 기법을 제공한다. 하나의 코어 당 한 번에 스레드를 하나 씩만 처리할 수 있으므로 thread가 4개이고 core가 두 개라면 아래 그림 3과 같이 실행될 것이다.

Parallel execution on a multicore system[그림 3] multicore system에서의 병렬 실행


운영체제는 위 그림 3처럼 병렬 실행이 될 수 있도록 여러 코어를 활용하는 scheduling algorithm을 제공해야 한다. 프로그래머도 마찬가지로 multi core의 장점을 활용하기 위해 thread를 잘 사용해야 한다. multi-core programming을 할 때 고려해야 할 5가지 사항이 아래에 나와있다.

      • Dividing activities: Process를 독립된 병행가능 task로 나누는 작업

      • Balance: task들이 균등한 기여도록 가지도록 하는 것

      • Data spliting: 각 task에서 개별적으로 접근 가능한 data가 있어야 한다.

      • Data dependency: 어떤 data가 task 사이에 종속성을 가질 때 동기화를 해야한다.

      • Testing and debugging: 단일 thread와 달리 다양한 실행 경로가 존재하므로 test와 debugging이 힘들다.


2. Multithreading Models

두 가지 타입의 thread가 있다. 하나는 프로그래머가 사용하는 user thread고, 다른 하나는 kernel이 사용할 kernel thread이다. user thread는 kernel thread 위에서 관리되며 kernel의 지원 없이 관리된다. 반면에 kernel thread는 운영체제에 의해 직접 지원되고 관리된다. Linux, Windows, Mac OS 등 거의 모든 현대 운영체제들은 kernel thread를 지원한다.

user thread와 kernel thread는 연관 관계가 존재해야 하며, 일반적으로 앞으로 나올 세 가지 방법들 중 하나를 사용한다.


2.1 Many-to-One Model

다수의 user thread가 하나의 kernel thread에 연관된다. thread 관리는 사용자 공간에 존재하는 thread library에 의해 진행되며 효율적이다. 하지만 한 thread가 blocking system call을 할 경우 전체 process가 block된다.왜냐면 kernel thread가 하나의 CPU에만 접근 가능하므로, many-to-one model에선 user thread들에 여러 CPU당(core)를 할당되도록 할 수 없기 때문이다. Solaris의 green threads와 GNU Portable thread가 과거에 이 model을 사용했다. 요즘에는 거의 사용하지 않는다. many-to-one model은 아래 그림 4와 같다.

Many-to-One Model[그림 4] Many-to-One Model


2.2 One-to-One Model

kernel thread를 user thread 하나 당 하나 씩 만든다. 어떤 user thread가 blocking system call을 하더라도 각각의 kernel thread가 다른 CPU(core)를 user thread에 할당할 수 있으므로 many-to-one model보다 더 많은 병렬성을 제공한다.

그렇지만 user thread를 생성할 때마다 kernel thread를 생성해야 하므로 overhead가 발생하고 system을 느려지게 할 수 있다. 그래서 대부분 이 모델을 구현할 때 만들어질 수 있는 thread 수를 제한한다. Windows와 Linux가 one-to-one model을 구현하고 있다. one-to-one model은 아래 그림 5와 같다.

One-to-One Model[그림 5] One-to-One Model



2.3 Many-to-Many Model

앞서 소개한 many-to-one, one-to-one model의 장점을 살려 user thread 개수와 같거나 적은 개수의 kernel thread를 만들고 multiplex한다. user는 user thread를 제한 없이 만들 수 있다. 그리고 blocking system call이 전체 system을 block 하지 않는다. 또한 kernel 개수가 one-to-one model보다 적으므로 앞서 말한 model 두 가지의 단점들을 어느 정도 해결했다.

Many-to-Many Model[그림 6] Many-to-Many Model


이 모델을 변형한 two-level model도 있는데, 아래 그림 7과 같다. multiplex를 유지하면서 어떤 user thread는 kernel thread에 one-to-one으로 연관되도록 허용한다. Solaris 운영체제가 Solaris 9 이전 버전에서 이 model을 지원했으나, Solaris 9부터는 one-to-one model을 사용한다.

Two-level Model[그림 7] Two-level Model


3. Thread Library

Thread library는 프로그래머에게 thread를 생성하고 관리하도록 API를 제공한다. 두 가지 방법이 있는데, 첫 번째는 kernel의 지원없이 완전히 user space에서만 library를 제공하는 것이다. 두 번째는 운영체제에 의해 kernel space에서 구현하는 것이다. 전자는 user space에서 구현된 API만 관련되고 kernel은 관련 없다. 후자는 kernel system call을 하게되고 kernel이 관계된다.

현재 아래 3가지 thread library가 주로 사용된다.


      • POSIX Pthreads: POSIX 표준 thread의 확장판이다. kernel 수준의 library이다.

      • Win32 threads: Windows system에서 제공되는 kernel 수준의 library이다.

      • Java threads: Java는 JVM 위에서 돌아가므로, JVM이 실행되고 있는 OS와 hardware에 기반해서 구현된다. Windows system에서는 Win32 threads로, UNIX와 Linux system에서는 Pthreads로 구현된다.

예제 코드가 필요할 시, 아래 참조 링크로 들어가 Pthreads, Win32 threads, Java threads의 예제를 살펴보자. (4.4.1, 4.4.2, 4.4.3 참고)


4. Thread Pool

thread는 생성하고 실행하는데 비용이 든다. 웹서버에서 매 요청마다 thread를 생성하면 생성하는데 소요되는 시간이 overhead가 된다. 또한, thread를 무작정 많이 만들면 context-switching이나 메모리 소모 등 시간, 공간적 자원이 많이 소모된다.

이런 문제점들을 해결할 수 있는 방법 중 하나가 thread pool이다.  기본 아이디어는 process가 시작할 때 일정한 수의 thread를 미리 pool로 만들어두는 것이다. 생성된 thread들이 대기하고 있다가, 요청이 들어오면 pool의 thread가 요청을 처리한다. 요청을 다 처리하면 pool에 다시 돌아간다.

thread pool은 아래와 같은 장점을 가진다.


      • thread 생성 비용이 없다.

      • thread의 개수를 제한하여 context-switching같은 비용을 줄인다.

thread pool의 예제는 아래 참조 링크에 들어가서 확인하자.


* 참조

Thread Library 예제

https://www2.cs.uic.edu/~jbell/CourseNotes/OperatingSystems/4_Threads.html


Thread Pool 예제

https://www.joinc.co.kr/w/Site/Thread/Advanced/ThreadPool

'프로그래밍 > OS' 카테고리의 다른 글

Scheduling Algorithms  (0) 2018.05.16
CPU Scheduling  (0) 2018.05.15
Multi Thread Programming  (2) 2018.01.29
프로세스 스케줄링(2)  (0) 2018.01.28
프로세스 스케줄링  (0) 2018.01.26
프로세스와 스레드 기초  (0) 2018.01.26
댓글
댓글쓰기 폼