Thread
하나의 프로세스 내에서 독립적으로 실행되는 작업 단위.
<특징>
- 공유 자원 : 같은 프로세스 메모리, 파일 핸들을 공유한다.
- 경량 생성 : 프로세스 생성보다 빠르고 리소스 소모가 적다.
Thread 사용하는 이유
- 가벼움 : 프로세스를 새로 만드는것은 매우 무거운 작업인데, thread생성은 쉽고 가볍다.
- 병렬성 : 여러 작업을 동시에 처리할 수 있다.(반응성이 좋아짐)
- 코드 간소화 : 코드를 더 단순하게 할 수 있고, 효율성을 높일 수 있다.
- 응답성 향상 : UI가 멈추지 않고 백그라운드 작업을 수행할 수 있다.(예: 타이핑, 철자 검사 동시에 진행)
MultiThread

- 스레드는 같은 주소 공간을 사용하기 때문에 서로 공유하기가 수월하다.
- 또한 프로세스를 또 만드는 것 보다 스레드를 확장하는게 더욱 경제적이다.
single Thread
-
특징
-
장점
-
단점
- 병렬성이 없다. -> CPU코어를 효율적으로 활용하지 못한다.
다중 Thread
- 특징
- 레지스터와 스택은 각 스레드 마다 독립적으로 갖는다.
- 코드, 데이터, 파일은 공유한다.

- 스레드가 많으면 병렬처리가 가능하다.
- single코어에서는 병렬처리가 보이게끔 context switching을 이용해 처리하지만,
- core의 수가 많아지면 스레드 개수에 따라 정말로 병렬적으로 처리할 수 있다.
Multithreading Models
1. Many-to-One Model
다수의 사용자 수준 스레드를 단일 커널 스레드에 매핑한다. 스레드 관리가 사용자 공간에서 이루어지기 때문에 경량화 된다.
<예시> : Solaris Green Threads, GNU Portable Threads

<장점>
- 생성 및 context switch 비용이 낮다.
- 커널 개입 없이 스레드 라이브러리가 직접 스케줄링을 처리한다. (system call을 사용한 커널 모드 전환이 필요 없음.)
- 커널 모드 전환이 필요없는 이유는 user thread들 끼리는 사용자 모드에서 현재 스레드의 레지스터, 스택등을 저장하고 context switching을 하기 때문이다.
<단점>
- 한 therad가 블로킹이 되면, 전체 프로세스가 차단되는 단일코어 한계가 존재한다.
2. One-to-One Model
각 사용자 스레드를 개별 커널 스레드에 1:1 매핑한다.
병렬성과 멀티코어 활용이 가능하다.
<예시> : Window NT/XP/2000, Linux, Solaris 9 이상

<장점>
- 안정성 : system call 블로킹이 다른 스레드에 영향을 미치지 않는다.
<단점>
- 커널 스레드 생성 오버헤드로 인해 자원 소모가 많이 든다.
3. Many-to-Many Model
사용자 스레드와 커널 스레드를 유연하게 매핑한다. 동적 스레드 풀 관리로 효율성을 극대화 한다.
OS가 필요한 커널 스레드를 생성할 수 있다.
<예시> : Solaris 9 이전 버전들, Window ThreadFiber pakage등

<장점>
- 동시에 여러 커널 스레드를 사용해, 병렬성을 보장한다.
<단점>
4. Two-level Model
Many-to-Many모델을 확장해 특정 사용자 스레드는 직접 kernel 스레드에 매핑한다. (하이브리드 형태)
<예시> : IRIX, HP-UX, Solaris 8....등

<장점>
- 중요한 스레드에 우선순위를 부여할 수 있다.
- 일반 스레드는 동적 매핑으로 오버헤드가 감소한다.
<단점>
추가적으로 보통 웹서버는 Many-to-Many모델을 통해 확장성 위주로 구현을 하고, 게임같은 경우에는 One-to-One모델로 병렬성을 활용해 구현을 한다.
Thread Library
Thread Library는 프로그래머가 스레드를 생성하고 관리할 수 있도록 API를 제공하는 소프트웨어 라이브러리다.
개발자는 손쉽게 스레드를 만들고, 실행하고, 동기화하는 등의 작업을 수행할 수 있다.
-
User Space에서 라이브러리
: 스레드 관리가 운영체제 커널과 별개로 사용자 영역에서 이루어짐.
: context switching이나 스케줄링 등 대부분의 작업이 라이브러리 내부에서 처리되어 커널 개입이 적다.
-
Kernel Level에서 운영체제가 지원하는 라이브러리
: 스레드 관리 및 스케줄링이 운영체제 커널에서 직접 이루어 진다.
: 각 스레드는 커널에 의해 관리되므로, 멀티코어 환경에서 진정한 병렬 실행이 다능하다.
Threading Issue
멀티스레드를 사용할 시 발생할 수 있는 주요 문제점과 해결방안에 대해서 알아보도록 하자.
1. fork()와 exec()의 의미론
- 문제점 : 멀티스레드 프로세스에서 fork()시스템 호출 시, 모든 스레드를 복제할지 아니면 호출한 스레드만 복제할지 명확하지 않는다.
- exec()가 fork()이후 실행이 되면, 모든 스레드가 교체되기 때문에 복제된 스레드가 의미가 없어짐.
- 해결법 : fork() 후 exec()을 호출하지 않는 경우, 호출 스레드만 복제하는 방식이 일반적이다.
2. Thread cancelled
목적 : 실행중인 스레드를 강제로 종료시키는 메커니즘.
| 방식 | 특징 | 예시 |
|---|
| Asynchronous 취소 | 즉시 스레드 종료한다. 누수 또는 데이터 불일치 리스크 | 웹 브라우저 페이지 로딩 종료 |
| Deferred(지연) 취소 | 스레드가 안전한 취소 지점에서 주기적으로 종료 여부 확인 | 병렬 데이터베이스 쿼리 중단 |
3. Signal Handiling
목적 : 시그널을 어떤 스레드에 전달할 지 결정해야 한다. (시그널: 긴급 알림 개념)
-
Unix환경에서 시그널 처리
- 각 스레드가 시그널을 받을 지 말지(block) 결정할 수 있음, 보통 시그널 받기로한 스레드중에서 가장 먼저 준비된 스레드가 받아서 처리한다,
- kill(pid, signal) - pid를 가진 프로세스에게 보낸다.(전체 전송)
- pthread_kill(tid, signal) - 스레드ID(tid)를 가진 특정 스레드에 보낸다.
-
Window 환경에서 시그널 처리
- 시그널 개념을 사용하지 않는다.
- APC : 대신 APC를 사용해서 유닉스의 시그널과 비슷한 비동기적인 알림 및 처리를 구현한다.
4. Thread Pools
목적 : 스레드 생성/삭제 오버헤드를 줄이고 자원 사용량을 제한한다.
- 작동 방식
- 미리 생성된 스레드 풀에서 작업을 할당받아 사용한다.
- 작업 완료 후 풀에 반환되어 재사용한다.
- 장점
- 응답 시간이 단축된다.(스레드 생성시간 제거)
- 시스템 과부화 방지(풀 사이즈 제한)
- ex) 웹 서버가 동시 요청을 Pool로 관리한다.
5. Therad Specific Data
필요성 : 스레드가 고유한 데이터를 독립적으로 관리해야 할 수 있게 해준다.
- 여러 스레드는 메모리 공간을 공유한다. -> 전역변수와 같은 데이터는 여러 스레드가 동시에 수정하려고 하면 Race Condition이 발생할 수 있다.
- 따라서 각 스레드마다 별도의 데이터를 따로 가질 수 있게 해준다.