목차
스레드(Thread)
애플리케이션은 여러 작업(task)를 할 수 있습니다. 디스플레이를 업데이트하고, 네트워크 통신을 하며, 데이터를 가지고 올 수도 있습니다. 이때 여러 프로세스로 각각의 일을 하는 것보다 한 프로세스가 내부에서 여러 실행 흐름, 실행 유닛을 가지는 방식이 더 단순한 코드와 효율성 증대되고 더 가볍습니다. 커널과 많은 프로그램이 현재 멀티스레드 방식을 사용합니다.
프로세스 속 스레드는 스택, PC(Program Counter. 레지스터 실행 위치), 레지스터를 제외하고 code, data, files, heap 공간을 공유합니다. 프로세스는 각각 완전히 격리된 느낌이고(철수네 집, 영희네 집) 스레드는 한 프로세스 내에 존재하는 개별적인 느낌입니다(철수네 집 "거실", "화장실", "주방)
그렇기에 스레드는 부모/자식 관계가 아닌 메인/서브의 관계로 표현됩니다.
-장점-
- 대응성(Responsiveness) : 프로세스 일부가 차단된 경우에도 지속적인 실행이 가능합니다
- 리소스 공유 : 스레드는 프로세스의 리소스를 공유하며, 이는 공유 메모리나 메시지 패싱보다 쉽습니다. 이는 통신 비용도 절감되고 메모리도 절약됩니다.
- 경제적 : 프로세스 생성보다 비용이 싸고 스레드 스위칭이 Context 스위칭보다 적은 오버헤드(Overhead)를 갖습니다.
(스레드들은 같은 메모리 공간을 공유하기 때문에, CPU의 상태 정보 등만 변경하면 됩니다. 프로세스는 변경처리와 새로운 캐시 정보 등을 로드해야합니다.) - 확장성 : 프로세스가 멀티코어 아키텍처의 이점을 활용가능합니다.
멀티코어 - 병행 VS 병렬
병행(Concurrency) : 사람 1명, 코어 1개가 멀티태스킹, 여러 일을 합니다.
병렬(Parallelism) : 실제로 물리적으로 따로 실행합니다. 사람이 여러명, 코어가 여러개
병렬은 2가지 타입의 병렬이 있습니다.
1. Data 병렬 : 각 코어가 데이터를 쪼개서 같은 일을 하는 경우
2. Task 병렬 : 각 코어가 동일한 데이터를 가지고 각각 다른 일을 하는 경우
사용자 스레드, 커널 스레드
사용자 스레드 : 사용자 레벨 스레드 라이브러리에서 관리되며 POSIX Pthreads, Windows threads, Java threads가 대표적입니다.
커널 스레드 : 커널에 의해 제공되며 각 OS에 포함됩니다.
* 스케줄링 단위 : 과거 스케줄링의 기본단위는 프로세스로 커널은 사용자 스레드를 모르던 시기가 있었습니다. 그때는 프로세스가 자신에게 배정된 시간을 직접 스레드에 배분하여 병행만 가능했었습니다. 현재는 스케줄링의 기본 단위가 스레드이기 때문에 한 프로세스에 여러 스레드도 병렬실행이 가능합니다.
멀티스레딩 모델
1. Many-to-One (모든 사용자 프로세스에 상응하는 커널 스레드가 1개만 있다!)
많은 사용자 레벨 스레드가 하나의 커널 스레드에 매핑되는 형태입니다.
오직 순간순간에 하나의 스레드만 커널 스레드에 매핑될테니 다중 스레드가 병렬 실행될 수는 없으며, 그렇기에 하나의 스레드가 블록되면 나머지 전체도 블록됩니다.
장점 : 원하는 만큼 사용자 스레드를 생성할 수 있습니다.
2. One-to-One (사용자 스레드 - 커널 스레드 1:1 매핑)
각 사용자 스레드가 각 커널 스레드와 1:1로 매핑됩니다.
장점 : 스레드가 블록되어도 다른 스레드 실행 가능하고, 여러개의 스레드를 다중 코어에 매핑할 수 있습니다.
단점 : 1:1매핑이기에 사용자 스레드를 무한정 생성할 수 없습니다.
3. Many-to-Many
여러 사용자 스레드가 여러 커널 스레드에 매핑되는 형태입니다.
장점 : 사용자 스레드를 마음대로 생성 가능하고, 멀티코어에서 병렬로 실행 가능합니다.
단점 : 구현이 매우 어렵습니다...
스레드 라이브러리
스레드 라이브러리는 스레드를 생성/관리하는 API를 제공합니다. 아래와 같이 2가지 주요 방법이 있습니다.
1. 사용자 스페이스에서의 라이브러리
2. OS에게 제공받는 커널 레벨 라이브러리 (시스템 콜에 결과)
POSIX Pthreads : 사용자 레벨 or 커널 레벨
Windows : 커널 레벨
Java threads : OS별 변동
POSIX Pthreads
Pthreads는 규약/명세(Specification)이지 구현(implementation)이 아닙니다. 그 예시로 Pthread 라이브러리간에 호환이 안될 수 있고 그런 경우 np(not portable) 표시가 되어있습니다. 보통 UNIX기반 OS(LINUX, Mac OS X)에서 사용됩니다.
pthread_create(pthread_t *thread_ID, const pthread_attr_t *attr, void *(*start_routine)(void *), void* arg) : 스레드의 ID, 속성, 실행할 함수 포인터(void * 리턴값에 인수로 void *를 가진 * start_routine이 주소인 함수), 함수 인자로 구성되며 스레드가 해당 함수를 실행합니다. 내부적으로 clone() 시스템 콜을 사용합니다.
★프로세스와 스레드에 대한 고찰 : LINUX OS에서는 스케줄링에 단위를 프로세스, 스레드라고 하지않고 작업(task)라고 합니다. 그 이유는 프로세스와 스레드가 본질적으로는 크게 차이가 없다는 관점이라고 생각합니다.
fork와 pthread_create는 내부적으로 clone()이라는 시스템 콜을 사용한다고 합니다.
clone() : Data Share. PID는 다른상태. task_struct point(링크로 처리합니다.)
fork() : Data copy. PID는 다른 상태. task_struct copy(복사로 처리합니다)
pthread_create() : Data Share, PID는 프로세스와 동일한 상태
실질적으로 프로세스와 스레드는 추상적인 개념이고 실 구현은 구역에 대한 옵션적인 차이이지 아예 동떨어진 별개의 개념이 아닌 동일한 개념으로 봐도 되기에 리눅스에서는 task라는 개념으로 스케줄링을 한다고 생각합니다. 먹을걸로 치자면 떡볶이에서 떡볶이, 짜장 떡볶이, 로제 떡볶이같이 옵션은 다르지만 개념을 통틀어 떡볶이로 관리한다고 생각합니다.
이외 exit, join 등등 실구현 부분은 POSIX manual을 보는 것으로...
스레드 풀
병렬 작업이 많아지면서 스레드 개수도 점점 늘다보면 관리가 힘들어집니다. 이런 문제점을 해결하기 위해 스레드에 미리 제한된 개수를 정해놓고, 그 개수만큼 스레드를 작업 큐 속에 대기시키면서 코어가 스레드를 맡아 처리하게 관리해주는 것이 스레드 풀입니다.이러면 언제나 전체 개수가 일정하니 일정한 task로 애플리케이션의 성능 저하를 막습니다.
OpenMP (Open Multi-Processing)
OpenMP는 공유 메모리(한 PC) 다중 처리 프로그래밍 API라고 합니다. 병렬 수행을 위한 멀티스레드 기반 표준 API입니다.
컴파일러 지시어 #pragma omp parallel 이후 { 에서 논리적인 코어의 수만큼 스레드를 만들고, } 에서 그 스레드들을 join 대기하는 방식입니다.
omp paralle 뒤에 for을 붙여서 for문에 대한 병렬 수행도 가능합니다. 추가 옵션적인 것으로 스레드를 논리 코어 개수만큼이 아니라 지정해서 만들 수 있고[num_threads(N)], 순서를 변경할 수도 있습니다[schedule(dynamic)].
TLS (Thread - Local Storage)
스레드는 자신이 속한 프로세스의 데이터를 공유하지만 경우에 따라서 자신만의 데이터가 필요할 수도 있습니다.(스레드별 고유 전역, 정적변수 등) 이런 경우 TLS는 스레드별 저장공간을 마련해주는 방법입니다. 전역변수인데 스레드마다 고유한 개별 전역변수를 줍니다.
스레드 풀을 사용하면 사용자는 스레드 생성에 관여하지 않기 때문에 TLS가 유용하다고 합니다.
*추가적으로 서버 같은 데서도 멀티스레드 환경에서 동기화를 위해 락을 걸어주거나 하는 부분에서 갑자기 한 부분에 자잘한 락 요청이 너무 많아 오히려 문제가 생길 때, TLS를 활용하여 최대한 일감을 TLS에 모아서 한번에 갖다 주는 방식?으로 쓰이는 것 같습니다..
'강의 > OS' 카테고리의 다른 글
OS - 동기화 툴 (0) | 2023.07.16 |
---|---|
OS - CPU Scheduling (0) | 2023.07.13 |
OS - Processes (0) | 2023.06.27 |
OS - Structure (0) | 2023.06.26 |
CPU스케줄링(5장) - 시험 요약 (0) | 2023.04.20 |