OS 스레드와 유저 스레드 그리고 스레딩 모델 비교

사용자가 작성한 프로그램은 OS를 통해 H/W를 사용한다.
하드웨어 스레드의 이해
하드웨어 스레드는 CPU의 물리적 코어가 동시에 처리할 수 있는 작업 단위를 의미한다.
일반적으로 CPU 사양에서 언급되는 스레드 수가 바로 이 하드웨어 스레드를 가르킨다. 하드웨어 스레드는 CPU 스레드라고도 한다.
코어(Core)의 고민:
메모리에서 데이터를 기다리는 시간이 꽤 오래 걸린다. 메모리를 기다리는 시간동안 코어가 아무일도 하지 않는다면 낭비이기 때문에, 메모리를 기다리는 동안 다른 스레드를 실행하는건 어떨까? 라는 아이다가 있다.
메모리를 기다리는 동안 독립적으로 다른 무언가랄 실행하는 것이 CPU에 적용된다.
CPU 코어와 하이퍼스레딩

이처럼 코어의 사용률을 극대화 시키기 위해서 그림처럼 두 개의 서로 다른 스레드를 실행시키는 데, 여기서 이 스레드를 Hardware Thread라고 한다.
인텔에서는 hyeper-thrading으로 명칭했다. 1개의 물리적 코어마다 하드웨어 스레드를 2개씩 두는 것을 의미한다.
하드웨어 스레드는 OS 관점에서 볼 때 가상의 코어이다. 만약 싱클 코어 CPU에 하드웨어 스레드가 2개라면 OS는 이 CPU를 듀얼 코어로 인식하고 듀얼 코어에 맞춰 OS 레벨의 스레드들을 스케줄링한다.
하드웨어 스레드 구성 예시
듀얼 코어 CPU (하이퍼스레딩 적용): 2개의 물리적 코어, 4개의 하드웨어 스레드
쿼드 코어 CPU (하이퍼 스레딩 미적용): 4개의 물리적 코어, 4개의 하드웨어 스레드
옥타 코어 CPU (하이퍼 스레딩 적용): 8개의 물리적 코어, 16개의 하드웨어 스레드
OS 스레드와 유저 스레드
OS 스레드의 특징
일반적으로 알고있는 스레드 개념이 OS 스레드이다. OS 스레드를 알기 위해서는 커널의 개념이 필요하다.
OS 스레드는 OS 커널 레벨에서 생성되고 관리되는 스레이드이고, CPU에서 실제로 실행되는 단위, CPU 스케줄링의 단위 이다.
즉, CPU에서 실제로 실행되는 것은 OS 스레드이고, OS 스레드의 컨텍스트 스위칭은 커널이 하는 행위이다.
사용자 코드와 커널 코드 모두 OS 스레드에 의해 실행된다.
또, OS 스레드는 "네이티브 스레드, "커널 스레드", "커널레벨 스레드", "OS레벨 스레드" 라고도 불린다.
Q: OS 스레드 8개가 hyper-threading이 적용된 인텔 듀얼코어 위에서 동작하면, OS 스레드는 어떻게 코어에 균등하게 할당할 수 있을까? A: 하드웨어 스레드가 총 4개이니까, OS에서는 이를 CPU로 인식한다. 따라서 8개의 OS 스레드를 각 코어에 2개씩 할당한다.
유저 스레드의 특징
유저 스레드는 User Program Level과 관련된 스레드이다. 스레드 개념을 프로그래밍 레벨에서 추상화 한 것이다.
즉, 유저 스레드는 사용자 수준의 라이브러리에 의해 관리되는 스레드이다.
사용자 공간에서 생성 및 관리된며 경량화되어 있다.
코드에서 스레드 객체를 생성하고 실행시킴으로써 스레드를 동작시킨다.
유저 스레드가 CPU에서 실행 되려면 반드시 OS 스레드와 연결되어야 한다.
그럼 유저 스레드와 OS 스레드를 어떻게 연결시킬 것인가?
총 3가지 연결 모델이 존재하는데, 스레딩 모델을 이해하면 유저 스레드는 "OS와는 독립적으로 유저 레벨에서 스케줄링 되는 스레드. 모델링에서 나타내는 유저 스레드"와 같이, 다른 의미로 해석 될 수 있다.
스레딩 모델 비교

일대일 모델 (One-to-One)
Java에서 사용하는 기법이다. 스레드 객체를 생성하고 start()를 호출하면 JNI를 사용하여 OS 스레드를 생성한다.
이 모델은 유저 스레드와 OS 스레드가 1:1 매핑되는 모델이다. (각 유저 스레드가 별도의 OS 스레드에 매핑)
장점:
스레드 관리를 OS에 위임하기 때문에 스케줄링도 커널이 수행한다. 그래서 멀티코어 환경을 잘 활용한다.
병렬 처리가 가능하다.
하나의 프로세스 안에 유저 스레드와 매핑되는 3개의 OS 스레드가 존재할 때, 한 개의 유저 스레드가 block I/O를 실행하면 매핑된 OS 스레드 또한 block I/O를 수행하여 blocking 된다. 하지만 남은 두 개의 스레드는 영향없이 잘 동작한다.
단점:
OS 스레드 생성의 오버헤드가 크고, 시스템 자원을 많이 사용한다.
1:1 모델이기 때문에 Race Condition이 발생할 가능성이 존재한다.
다대일 모델 (Many-to-One)
유저 스레드가 여러 개 존재하고, 한 개의 OS 스레드만 존재하는 모델이다.
장점:
컨텍스트 스위칭이 더 빠르다. 그 이유는 유저 스레드에서만 컨텍스트 스위칭이 발생하기 때문에 커널의 개입이 없다. 커널이 개입하지 않는것은 컨텍스트 스위칭이 빨리 끝날 수 있음을 의미한다. (유저 스레드 전환이 빠름을 의미)
OS 스레드가 한 개이기 때문에 OS 레벨에서 Reace Condition이 발생할 확률이 적다.
단점:
멀티 코어를 활용할 수 없다.
유저 스레드가 block I/O를 호출하면 OS 스레드도 block I/O를 호출하는데, OS 스레드가 한 개만 존재하기 때문에 block되면 모든 유저 스레드가 block 된다. (한 개 스레드가 블로킹되면 전체 프로세스가 블로킹 될 수 있다.)
이 문제를 해결하기 위해서 non-block I/O를 사용한다고 한다.
다대다 모델 (Many-to-Many)
일대일과 다대일의 장점을 합쳐놓은 모델이다. 유저 스레드가 여러 개 존재하고, 적절한 개수의 OS 스레드가 존재한다.
장점:
유저 스레드 간 스위칭이 빠르면서 멀티 코어 활용이 가능하다.
한 개의 스레드가 block 되어도 전체 유저 스레드가 block 되지 않는다. (남아있는 OS 스레드가 존재하기 때문)
단점:
구현이 복잡하고 스케줄링 오버헤드가 발생할 수 있다.
이러한 모델들은 각각의 장단점이 존재해서, OS나 프로그래밍 언어에 따른 모델을 채택하고 있다. 예를 들어 Java는 기본적으로 일대일 모델을 사용하지만, Go 언어의 고루틴은 다대다 모델과 유사한 방식을 채택한다고 한다.
Green 스레드
Java 초창기 버전은 다대일 스레딩 모델을 사용했다. 이 때 유저 스레드들을 그린 스레드라고 불렀다.
하지만 그린 스레드의 개념이 계속 확장되면서 지금은 OS와는 독립적으로 유저 레벨에서 스케줄링 되는 스레드를 의미한다. (유저 스레드 = 그린 스레드)
Kernel 스레드
앞에서 커널 스레드는 OS 스레드와 같은 의미라고 했지만, 다른 맥락에서는 OS 커널의 역할을 수행하는 스레드로 해석될 수 있다. 커널 코드를 실행하는. 즉, OS 스레드 역할을 담당하는 스레드를 의미한다.
Question
유저 스레드와 OS 스레드의 차이점
유저 스레드는 프로그래밍 레벨에서 추상회된 스레드를 의미한다. 프로그래머가 직접 생성하고 관리하며 CPU에서 직접 실행되지 않는다.
OS 스레드는 커널 레벨에서 생성되고 관리되는 스레드이다. CPU에서 실제 실행되는 단위이며, CPU 스케줄링의 대상이 된다.
하드웨어 스레드와 OS 스레드와의 관계
하드웨어 스레드는 물리적 CPU 코어 내에서 동작하는 실행 단위이다. OS는 하드웨어 스레드를 가상의 CPU 코어로 인식하고 하드웨어 스레드에 스케줄링 된다.
OS 스레드 갯수는 하드웨어 스레드 수 보다 많을 수 있으며 OS는 이들을 시분할 방식으로 스케줄링 한다.
블로킹 I/O가 스레드 실행에 미치는 영향을 각 스레드 모델별로 설명
일대일: 한 스레드가 블로킹 되어도 다른 스레드들은 계속 실행 가능. 블로킹 된 스레드에 해당하는 OS 스레드만 대기 상태가 된다.
다대일: 하나의 스레드가 블로킹 I/O를 수행하면 모든 유저 스레드가 블로킹된다. 단일 OS 스레드가 블로킹되므로 전체 프로세스가 대기 상태가 될 수 있다. 이 문제를 해결하기 위해 논-블로킹 I/O를 사용해야 한다.
다대다: 일부 스레드가 블로킹 되어도 다른 스레드들은 영향을 받지 않고 계속 실행이 가능하다.
비동기 I/O와 논-블로킹 I/O가 스레드 관리에 미치는 영향
비동기 I/O: 스레드가 I/O 작업 동안 블록되지 않는다. 적은 수의 스레드로 많은 I/O 작업을 처리할 수 있다. 이벤트 루프 패턴과 어울린다. 단일 스레드에서도 높은 동시성을 달성할 수 있다.
논-블로킹 I/O: I/O 작업 즉시 완려 여부를 확인한다. 스레드가 다른 작업을 수행할 수 있게하고, 폴링 방식으로 I/O 상태를 확인해야 한다.
refernce: Youtube 쉬운코드
Last updated