User threads : kernel support 없이 관리 된다. ( ex) Java Thread : O/S가 아닌 JVM이 관리)
장점 :
단점 :
하나의 스레드가 시스템 호출 등으로 중단되면 나머지 모든 스레드 역시 중단된다.
→ 커널이 프로세스 내부의 스레드를 인식하지 못하며 해당 프로세스를 대기 상태로 전환시키기 때문이다.
하나의 스레드가 System Call을 하면 해당 프로세스 내 모든 스레드가 중단된다. (Blocking System call)
Kernel threads : O/S 에 의해 직접적으로 관리 된다.
장점 :
단점 :

다대일 모델(Many-to-one Model)
다중 thread를 사용하지만, kernel 입장에서는 user level에 thread가 몇 개나 존재하는지 알지 못하기 때문에 Scheduling같은 관리들이 user level에서 이루어진다.
→ 당연히 속도가 빠르고 thread를 생성하고 관리하기 쉽다.
한 개의 thread라도 system call을 수행하다가 block이 되면 kernel과 연결되어 있는 길이 “하나”뿐이기 때문에 모든 thread들이 block 된다.
결국 여러 user thread들 중 하나의 thread만이 kernel과 작업을 할 수 있다.
→ multicore 시스템에서 한 번에 하나의 thread만이 작업에 참여할 수 있어 “병렬(Parallel)” 작업이 불가능
<현재는 거의 사용하지 않는다.>
일대일 모델 (One-to-one Model)
다대일 모델과는 정반대의 특성들을 가진다.
→ user thread를 생성하면 kernel thread도 생성되는 형태로 구현.
user thread 하나 당 kernel thread가 하나씩 연결되어 있기 때문에 thread 하나가 block 되더라도 다른 thread들은 정상적으로 작동 가능
동시성 (Concurrency)이 보장됨 + multicore 시스템에서 여러 개의 thread들이 병렬(Parallel)로 실행 가능
thread 생성이 힘들고, 관리가 어렵기 때문에 thread가 많아지게 되면 시스템의 성능에 큰 부담을 줄 수 있다.
→ 시스템들은 thread의 최대 개수를 정해두어 관리하는 방법으로 overhead 방지
다대다 모델 (Many-to-many Model)
Kernel thread의 수는 시스템이나 하드웨어에 따라 결정되며,
user thread들은 user level의 스케쥴러에 의해 kernel thread들에게 복합적으로 연결된다.
Kernel thread가 여러 개 존재하기 때문에 multicore 시스템에서
병렬(Parallel) 수행이 가능.
다대일 모델, 일대일 모델의 장점을 결합한 형태
→ 많은 thread가 좀 더 손쉽게 관리되는 장점이 있지만, 구현이 어렵다.

void * runner : Java의 public void run() 메소드
pthread_create : Java의 Thread thread = New Thread();

Q1) How many unique processes are created? Ans) 6
Q2) How many unique threads are created? Ans) 8
Sol)

pid = fork();에서 부모 P0, 자식 P1이 생성
P0은 if문 아래의 fork();를 통해 자식 P2를 생성
부모 P0을 실행했으니, 자식 P1을 실행한다.
→ P1은 if문의 fork();를 통해 자식 P3를 생성
→ P1은 thread_create를 통해 쓰레드1을 생성 후, if문 밖의 fork();를 통해 자식 P4를 생성.
P1을 실행했으니 자식 P3를 실행한다.
→ P3는 thread_create를 통해 쓰레드2를 생성 후, if문 밖의 fork();를 통해 자식 P5를 생성.
프로세스는 "하나의 실행 흐름(Execution Flow, Control Flow)을 가지고 실행 중인 프로그램"이다. (Executing program with a single thread of control)
한 프로세스당 하나의 스레드가 존재하고, 두개의 스레드를 생성했으니 스레드는 총 8개이다.

Q) Line C, Line P에서의 value 값은?
Ans) Line C : 5, Line P : 0
Sol) 자식 프로세스에서 thread를 만들고 runner를 실행할 경우 전역변수 가 5가 된다.
이 때 쓰레드는 전역변수를 공유하므로 Line C에서는 5가 출력되고
Line P에서는 0이 출력된다.
Thread Pools
thread를 생성하고 소멸시키는 것 자체가 큰 overhead
너무 많은 thread가 생성되고 제대로 관리가 되고 있지 않을 시에는 시스템의 resource들을 효율적으로 사용하지 못함.
특정 개수의 thread들을 thread pool에 미리 만들어두고 thread가 필요할 때 thread들을 할당.
사용 완료 시 thread를 제거하지 않고 다시 thread pool에 반납해 다음 요청을 기다리게 한다.
→ 필요할 때 마다 thread를 생성할 필요가 없고 반납된 thread를 재사용하기 때문에 생성과 소멸로 인해 발생하는 overhead감소
Fork & Join
pThread의 fork-join과 같은 모델이기 때문에 explicit Threading(명시적 스레딩)이라 생각할 수 있다.
하지만 implicit Threading에서 개발자가 직접 스레드 생성을 하지 않는다.
→ fork()시스템콜만 호출해주고, 스레드 생성 & 관리는 라이브러리가 수행
OpenMP
OpenMP는 공유 메모리 영역에서 병렬 프로그래밍을 가능하게 해주는 C, C++, FORTRAN으로 작성된 API와 컴파일러 디렉티브의 집합.
프로그램의 code 중에 병렬(Parallel)로 실행될 수 있는 영역에 #pragma omp parallel 이라는 구문을 삽입하면 CPU의 코어 개수에 맞게 thread를 생성, 해당 for문 안의 부분을 병렬(Parallel)로 실행
참고 :
Silberschatz et al. 『Operating System Concepts』. WILEY, 2020.