스레드 종류 - 하드웨어 스레드, OS 스레드, 네이티브 스레드, 커널 스레드, 유저 스레드, 그린 스레드 #
우리가 작성한 프로그램의 동작방식 #
- 하드웨어
- OS Kernel
- User Program : 운영체제를 통해 하드웨어를 사용
Hardware thread #
- 코어(core)의 고민 : 메모리에서 데이터를 기다리는 시간이 꽤 오래 걸린다.
- 코어에서 프로그램이 실행될때 각종 연산 작업이 있을테고, 이를 위해 메모리에 접근하는 작업들이 있다. 이 코어에서 실행되는 연산 작업에 비해 메모리에서 데이터를 기다리는 시간이 더 오래 걸린다. 이는 코어를 낭비하고있다는 말과 같다.
- 메모리를 기다리는 동안 다른 쓰레드를 실행하는건 어떨까?
- 예시) 코어 -> Computing 작업 -> 메모리에 접근하여 데이터 처리 -> Computing 작업 -> 메모리에 접근…
- 코어가 쉬고있을때마다 코어를 낭비하는 것과 같다.
- 이를 해결하기 위해, 메모리에 접근하는 동안 독립적으로 또다른 무언가를 실행하면 어떨까?
- 1개의 코어에서 2개의 쓰레드를 실행하는 것 -> 이 각각의 쓰레드를 Hardware Thread라고 한다.
- 이를 인텔의 Hyper-threading 이라고 한다.
- 물리적인 코어마다 하드웨어 스레드가 2개다.
- Hardware Thread : OS 관점에서는 가상의 코어
- 싱글코어 CPU에 하드웨어 스레드가 2개라면, OS는 이 CPU를 듀얼 코어로 인식하고, 이에 맞춰서 OS 레벨의 스레드들을 스케줄링한다.
- 이를 인텔의 Hyper-threading 이라고 한다.
OS Thread #
- OS Kernel 영역에 해당되는 부분
- 커널(kernel)
- 운영체제의 핵심
- 시스템의 전반을 관리/감독하는 역할
- 하드웨어와 관련된 작업을 직접 수행
- OS Thread
- OS 커널 레벨에서 생성되고 관리되는 스레드
- CPU에서 실제로 실행되는 단위, CPU 스케줄링의 단위
- OS 스레드들의 컨텍스트 스위칭은 커널이 개입 -> 비용 발생
- 사용자 코드와 커널 모드 모두 OS 스레드에서 실행된다.
- 우리가 작성한 코드가 OS 스레드로 실행되고, system call을 사용하면 커널 모드로 전환되고, 여기서 커널 코드가 실행되는데 이도 OS 스레드에서 실행된다.
- native 스레드, 커널 스레드, 커널-레벨 스레드, OS-레벨 스레드 라고 불리기도한다.
- OS 스레드 8개가 하이퍼 스레딩이 적용된 인텔 듀어코어 위에서 동작한다면 OS 스레드들을 어떻게 코어에 균등하게 할당할까?
- 코어마다 하드웨어 쓰레드가 2개씩 있고, OS 입장에서는 하드웨어 쓰레드 각각이 코어로 인식되고, 이 코어 당 쓰레드 2개씩 할당한다.
User Thread #
- 유저-레벨 쓰레드라고 불리기도한다.
- 스레드 개념을 프로그래밍 레벨에서 추상화 한것이다.
Thread thread = new Thread(); thread.start();
- 자바에서 제공하는 Thread라는 Class 사용 - start()의 구현부에서 start0() 메서드를 호출하는데, 이는 JNI라는 기술을 통해 OS SystemCall을 호출한다.
- 리눅스라면 clone 이라는 system call 호출 -> 리눅스에서는 OS 레벨의 쓰레드를 1개 생성하게된다. 이 쓰레드는 User-level의 쓰레드와 연결이 된다.
- 유저 스레드가 CPU에서 실행되려면 OS 스레드와 반드시 연결되어야한다.
- (= 기본적 CPU에서 실행되는 단위는 커널 스레드이기 때문! 따라서 유저 스레드는 반드시 커널 스레드와 연결이 되어야 하고, 그 후에 커널 스레드가 CPU에서 실행이 된다.)
- 유저 스레드와 OS 쓰레드를 어떻게 연결할까?
-
- One-to-One model : start() 하는 순간, OS 레벨의 쓰레드를 생성하여 1:1로 연결한다.
- 쓰레드 관리를 OS에 위임한다. (스케줄링 포함)
- 스케줄링도 커널이 수행한다.
- CPU가 만약에 멀티코어를 가진다고 해도, 이 멀티코어에 OS 쓰레드를 잘 분배하여 동작시키면, 1:1로 분배되는 유저 쓰레드도 멀티코어를 잘 활용하게된다.
- 한 쓰레드가 block이 되도, 나머지 쓰레드에는 영향없이 잘 동작한다.
- race condition 발생 가능성 있음
-
- Many-to-One model : User 레벨의 쓰레드가 여러개있고, OS 레벨의 쓰레드는 1개만 있다. N:1로 연결한다.
- Context Switching이 더 빠르다. (User 레벨에서 발생하기때문에 커널의 개입이 없다.)
- OS 쓰레드만 보면 싱글 쓰레드이기 때문에 OS 레벨에서 race condition이 발생할 가능성이 거의 없다. (User Thread는 있다.)
- 멀티코어를 활용할 수 없다. 실제로 코어에서 실행되는 쓰레드는 OS 쓰레드이기 때문이다.
- 첫번째 User-Thread가 blocki I/O를 호출했을때, OS 쓰레드에서 block I/O를 호출하게되어, 다른 User-Thread 모두 block된다.
-
- Many-to-Many model : User Thread, OS Thread 가 모두 N:N으로 연결된다.
- 위 1), 2) 방법의 장점을 살린 방법
- 구현이 복잡하다.
-
- 기술 문서에서는 OS와는 독립적으로 유저 레벨에서 스케줄링되는 스레드라고 한다.
- Many-to-One model, Many-to-Many model 로 볼 수 있다.
Green Thread #
- Java 초창기 버전은, Many-to-One 스레딩 모델을 사용, 이때 유저 스레드들을 그린 쓰레드라고 호칭했다.
- OS와는 독립적으로 유저 레벨에서 스케줄링되는 스레드
- Many-to-One model, Many-to-Many model 로 볼 수 있다.
Kernel Thread #
- OS 커널의 역할을 수행하는 스레드
- Youtube 강의 : https://www.youtube.com/watch?v=vorIqiLM7jc
- https://velog.io/@chanyoung1998/%EC%8A%A4%EB%A0%88%EB%93%9C%EC%9D%98-%EC%A2%85%EB%A5%98%ED%95%98%EB%93%9C%EC%9B%A8%EC%96%B4-%EC%8A%A4%EB%A0%88%EB%93%9C-OS-%EC%8A%A4%EB%A0%88%EB%93%9C-%EC%9C%A0%EC%A0%80-%EB%A0%88%EB%B2%A8-%EC%8A%A4%EB%A0%88%EB%93%9C