쓰레드와 병행성
개요
쓰레드란?
- 쓰레드는 프로세스 내에 있는 것으로 CPU 이용의 기본 단위이다.
쓰레드 구성요소
- 쓰레드 ID
- 프로그램 카운터
- 레지스터 집합
- 스택
멀티쓰레드의 필요성
- 현대에서 사용되는 시스템은 대부분 멀티 쓰레드를 지원한다.
- 프로세스 생성은 비용이 많이 드는 반면, 쓰레드 생성은 비용이 비교적 저렴하다.
- 멀티쓰레드를 사용하면, 코드를 간단하게 하고 효율은 올라가게 한다.
-
커널은 일반적으로 멀티쓰레드를 지원한다.
- 멀티 쓰레드 예시
- 문서 편집 응용프로그램을 예시로 삼아, 멀티 쓰레드에 대한 예시를 알아보자.
- 문서 편집 App에서 사용되는 쓰레드 업무
- 화면 갱신
- 키보드 입력 데이터 가져오기
- 철자 확인
- 네트워크 요청에 응답하기
클라이언트&서버 구조에서의 쓰레드
- 클라이언트의 요청당 쓰레드를 서버에서 생성하여 응답한다.
쓰레드 사용시 장점
- 응답성 향상
- 병렬적으로 업무를 처리할 수 있으므로, 응답성이 향상된다.
- 자원공유
- 경제성
- 프로세스를 새로 만드는 것보다 쓰레드를 생성하는 것이 더 저렴하다.
멀티코어 프로그래밍
- 현대의 CPU는 멀티코어 CPU이다.
- 한 개의 칩에 여러 개의 CPU(core)가 존재한다.
Parallelism과 Concurrency
Parallelism이란?
- 병렬 실행
- 한 시점에 여러 개 작업을 동시에 실행한다.
Concurrency란?
- 병렬 실행
- 한 개 이상의 작업이 수행되게 한다.
- 즉, Time Sharing을 생각하면 된다.
Parallelism과 Concurrency 를 구분할 수 있어야 한다.
Concurrency vs Parallelism
- Concurrency
- Concurrency는 단일 코어에서 사용된다.
- 즉, Time Sharing을 의미한다.
- 시간을 분할하여, 여러 Task를 번갈아가며 수행한다.
- Parallelism
- Parallelism은 멀티 코어에서 사용된다.
- 진짜 동시 실행을 의미한다.
멀티쓰레드 사용시 고려해야하는 점
- 멀티쓰레드를 사용하면, 개발자는 여러 문제를 고려해야 한다.
- 고려사항
- 작업 분리
- 균형
- 데이터 분리
- 데이터 종속성
병렬 실행 유형
병렬 실행을 하는 방법에는 2가지가 존재한다. 이는 아래와 같다.
- Data Parallelism (데이터 병렬)
- 배열처럼 이어진 여러 데이터들에 대해, 같은 Task을 병렬적으로 수행하는 것
-
즉, 데이터에 초점을 맞추고, 반복적인 메커니즘을 병렬적으로 수행하는 것
Loop의 각 Step을 병렬적으로 처리한다고 생각하면 된다.
- 주로 Vector Processing에서 사용된다.
- 예시
- 배열 a, b, c가 존재할 때,
c = a + b
에 대한 연산
- 배열 a, b, c가 존재할 때,
- Task Parallelism (테스크 병렬)
- 다양한 데이터에 대해, 서로 다른 Task를 수행하는 것
암달의 법칙
암달의 법칙이란?
- 암달의 법칙은 “순차 코드 부분과 병렬 부분에 대한 성능 향상율”을 의미한다.
암달의 법칙 공식
- 공식
- speadup : 속도 향상율
- S : 순차 코드 부분의 비율
- (1-S) : 병렬 코드 부분의 비율
- N : 프로세서의 개수
- 특징
- N이 무한대이면, 로 수렴한다.
예시 문제
- 문제
- 순차 코드 부분의 비율이 75%이고, 병렬 코드 부분의 비율이 25%이다.
- 그리고 프로세서가 1개에서 2개로 증가되었을 때, 속도가 얼마나 빨라졌겠는가?
- 풀이
- S = 0.75
- (1-S) = 0.25
- N = 2
- 따라서, 1.6배 빨라졌다.
유저 쓰레드와 커널 쓰레드
유저 쓰레드, 커널 쓰레드란?
- 유저 쓰레드
- 유저 쓰레드는 유저 레벨 쓰레드 라이브러리에 의해 동작하는 쓰레드이다.
- 유저 쓰레드는 “유저 스페이스에서 동작하는 쓰레드”이다.
- 유저 쓰레드는 커널 쓰레드의 도움을 받아 동작한다.
- 주요 유저 레벨 쓰레드 라이브러리
- POSIX에서 사용되는 Pthreads
- Windows에서 사용되는 threads
- Java에서 사용되는 threads
- 이것은 언어 레벨에서 쓰레드를 지원하는 것이다.
- 커널 쓰레드
- 커널에서 제공하는 쓰레드이다.
유저 쓰레드와 커널 쓰레드 간의 매핑 종류
유저 쓰레드와 커널 쓰레드가 서로 매핑하는 방식은 총 3가지가 있다. 이것은 아래와 같다.
- Many-To-One
- One-To-One
- Many-To-Many
Many-To-One
- 여러 유저레벨 쓰레드가 하나의 커널 쓰레드에 매핑된다.
- 한 개의 유저 쓰레드 봉쇄가 전부를 다 봉쇄시킨다.
- 왜냐하면, 커널 쓰레드가 하나이기 때문이다.
- 과거에 사용하던 방식이다.
One-To-One
- 사용자 쓰레드와 커널 쓰레드가 서로 일대일로 매핑된다.
- Many-To-One 보다 더 병렬성에서 우수하다.
- 유저쓰레드는 독립적으로 동작한다.
- 오버헤드 때문에 가끔, 프로세서당 동작하는 쓰레드 개수가 제한된다.
- 현대 시스템에서 사용되는 방식이다.
- 사용처
- Windows xp, 2000
- Linux
- Solaris 9 and later
Many-To-Many
- 많은 유저 쓰레드가 많은 커널 쓰레드에 매핑된다.
- 운영체제가 충분히 많은 커널 쓰레드를 만들도록 허용한다.
- 구현시 오버헤드가 발생하여, 사용되지 않는 방식이다.
Two-level Model
- Many-To-Many와 비슷한 방식이다.
- 하지만, 유저 쓰레드 수가 커널 쓰레드 수보다 적거나 같도록 제한한다.
쓰레드 라이브러리
쓰레드 라이브러리의 역할
- 쓰레드 라이브러리는 “쓰레드들을 만들고 관리하는 API를 프로그래머에게 제공”한다.
쓰레드 API 방식
쓰레드 API를 제공하는 방식은 아래와 같다.
- 라이브러리가 완전 유저 스페이스에 있는 방식
- 운영체제가 커널 레벨 라이브러리를 지원하는 방식
Pthreads
- POSIX 운영체제에서 사용되는 라이브러리이다.
- Pthreads 라이브러리는 유저 쓰레드와 커널 쓰레드 모두 지원한다.
- Pthreads 라이브러리는 UNIX 계열군의 표준 API이다.
-
Pthreads는 오직 명세(가이드)일 뿐이다. 이에 대한 구현은 각 벤더들이 한다.
-
Pthreads 예시 코드
Windows Thread 예시코드
Java Threads
- 쓰레드는 자바 프로그램 실행의 근본적인 모델이다.
- 자바 언어와 API는 쓰레드 생성과 관리를 풍부하게 지원한다.
- 언어 레벨에서 쓰레드를 지원한다.
암묵적 쓰레딩
암묵적 쓰레딩이란?
- 쓰레드를 점점 더 많이 쓰다보니, 프로그램 수행의 정확성을 지키기가 어려워졌다.
- 따라서 쓰레드 생성 관리 등을 프로그래머 대신, 컴파일러와 런타임 라이브러리에 맡긴 것을 암묵적 쓰레딩이라고 한다.
암묵적 쓰레딩의 방법
암묵적 쓰레딩을 하는 3가지 방법은 아래와 같다.
- Thread Pools
- OpenMP
- Grand Central Dispatch (GCD)
Thread Pools
- 수행해야 할 일들(Tasks)을 기다리는 쓰레드의 풀을 구성한다.
- 쓰레드를 그때그때 새로 만드는 것 보다, 미리 만들어두어 이미 존재하는 쓰레드로 서비스하는 것이 조금 더 빠르다.
- Pool의 사이즈 만큼의 쓰레드를 서비스 할 수 있다.
- Pool 사이즈 이상의 요청시, 사용 중인 쓰레드가 완료될 때까지 기다려야한다.
- 윈도우즈의 쓰레드 API도 Thread Pools 를 지원한다.
OpenMP
- OpenMP는 병렬 프로그램을 지원한다.
- 전처리기를 통해서 구현할 수 있다.
- 병렬 수행영역을 전처리기로 표기하여, 쓰레드를 사용하여 처리한다.
Grand Central Dispatch (GCD)
- GCD는 Apple 사의 기술이다.
^{}
을 통해, 병렬처리를 한다.- 해당 중괄호 안에 작성된 내용을 독립적으로 실행될 수 있는 작업단위로 처리한다.
- GCD의 종류
-
Serial (직렬)
-
Concurrent (병행)
위 두가지 모두 GCD가 지원한다.
-
- 성결대학교 컴퓨터 공학과 강영명 교수님 (2021)
- Siberschatz et. al., 『Operating System Concepts 10th Ed.』