
컴퓨터를 구성하는 하드웨어(CPU, Memory, Devices)와 하드웨어를 관리하고 컴퓨터 시스템 전반을 관리하는 OS(커널)가 있고 우리가 개발한 프로그램(Application)은 운영체제를 통해서 하드웨어를 사용하게 된다.
하드웨어 스레드
- OS 관점에서는 가상의(logical) 코어
- 인텔에서는 hyper-threading이라고 브랜딩하였다. -> 물리적인 코어마다 하드웨어 스레드가 두 개
- 예) 싱글 코어 CPU에 하드웨어 스레드가 두 개라면 OS는 이 CPU를 듀얼코어로 인식하고 듀얼 코어에 맞춰서 OS 레벨 스레드들을 스케줄링 한다.

OS 스레드(네이티브 스레드 == 커널 스레드 == 커널-레벨 스레드 == OS-레벨 스레드)
- OS 커널 레벨에서 생성되고 관리되는 스레드
- CPU에서 실제로 실행되는 단위, CPU 스케줄링의 단위
- OS 스레드의 컨텍스트 스위칭은 커널이 개입 -> 비용 발생
- 사용자 코드와 커널 코드 모두 OS 스레드에서 실행된다. (사용자 코드가 OS 스레드에서 실행 -> System call -> 커널 모드로 전환 -> 커널 코드 실행(커널 코드도 OS 스레드에서 실행) -> 유저 모드로 돌아옴)
- 예) OS 스레드 여덟 개가 하이퍼 스레딩이 적용된 인텔 듀얼코어 위에서 동작한다면 OS 스레드들을 어떻게 코어에 균등하게 할당할 수 있을까? -> 물리적 코어는 2개고 하이퍼 스레딩이 적용되어서 논리적으로는 4개고 OS 스레드 8개가 코어당 2개씩 할당된다.
* 시스템 호출(System calls): 운영체제는 커널 모드와 사용자 모드로 나뉘어 구동된다. 프로그램이 구동되는데 있어 파일을 읽어 오거나, 파일을 쓰거나, 혹은 화면에 메시지를 출력하는 등 많은 부분이 커널 모드로 사용한다. 시스템 콜은 이러한 커널 영역의 기능을 사용자 모드가 사용 가능하게, 즉 프로세스가 하드웨어에 직접 접근해서 필요한 기능을 사용할 수 있게 해준다.
커널
- 운영체제의 핵심
- 시스템의 전반을 관리/감독하는 역할
- 하드웨어와 관련된 작업을 직접 수행
유저 스레드(유저-레벨 스레드)
- 스레드 개념을 프로그래밍 레벨에서 추상화 한 것
- Thread thread = new Thread(); thread.start();
- 유저 스레드가 CPU에서 실행되려면 OS 스레드와 반드시 연결돼야 한다.
- 문서에 따라 OS와는 독립적으로 유저 레벨에서 스케줄링되는 스레드를 말하기도 한다. (그린 스레드랑 의미가 같음)
유저 스레드와 OS 스레드를 어떻게 연결시킬까?
One-to-One Model(커널 레벨 스레드 모델)
- 유저 스레드와 OS 레벨의 스레드가 1 : 1 관계로 연결
- 스레드 관리를 OS에 위임
- 스케줄링도 커널이 수행
- CPU 멀티 코어에도 OS 스레드가 잘 배분(할당) 시킬거니깐 멀티 코어를 잘 활용
- 한 스레드가 Block이 돼도 다른 스레드는 정상 동작
- 경쟁상태(Race Condition) 발생 가능성
- 자바 1.2 이후부터 사용중인 모델
- 기본적으로 자바는 threading model을 직접 JVM에서 관리하는 것이 아니라 그 아래 단의 OS에 위임을 합니다. 이건 소스코드를 보면 알 수 있는데요, jdk의 Thread 클래스의 소스코드를 보시면 start 메서드에서 start0메서드를 호출하는데요,, (아래 링크 691번 라인 참고) https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/java/lang/Thread.java#L691 이 start0는 private native void start0(); 로 되어 있습니다 (705번 라인) 여기서 native 키워드는 C나 C++ 처럼 다른 언어로 구현된 것을 호출하기 위해 사용되는 키워드이며, JVM은 이 키워드를 보고 JNI(Java native interface)를 통해 아래단의 OS 플랫폼에서 제공하는 라이브러리 메서드를 호출합니다 그렇기 때문에 OS 플랫폼에서 어떻게 라이브러리를 제공하는지 따라 one-to-one일 수도 있고 many-to-many일 수도 있습니다. 위 링크에서 Solaris OS의 경우에는 제공하는 라이브러리가 many-to-many로 동작하도록 구현됐기 때문에 many-to-many인 거고요, 하지만 우리가 가장 흔히 사용하는 윈도우나 리눅스 같은 경우에는 플랫폼 레벨에서 one-to-one model 방식으로 동작하도록 라이브러리를 제공합니다
* Race Condition: 공유 자원에 대해 여러 개의 프로세스가 동시에 접근하기 위해 경쟁하는 상태를 말한다.
Many-to-One Model(사용자 레벨 스레드 모델)
- 유저 스레드와 OS 레벨의 스레드가 M : 1 관계로 연결
- 컨텍스트 스위칭이 유저 레벨에서만 일어나기 때문에 커널이 전혀 개입을 하지 않게 되고 커널이 개입을 하지 않는다는 말은 컨텍스트 스위칭이 훨씬 빨리 끝난다.
- OS 스레드가 하나이기 때문에 Race Condition 발생 가능성이 적고 멀티 코어를 활용 못한다.
- 한 스레드가 Block이 되면 모든 스레드들이 Block이 된다. -> 그래서 Non Block I/O 방식을 사용한다.
Many-to-Many Model(멀티 레벨 스레드 모델)
- 현재 Java에서 사용하는 방식
- 유저 스레드와 OS 레벨의 스레드가 M : N 관계로 연결
- 하이브리드 스레드라고도 불리며 커널 스레드 개수가 사용자 스레드보다 같거나 적다.
- One-to-One Model 과 Many-to-One Model의 장점을 모아서 만든 Model
- 구현이 복잡하다.
- 한 커널 스레드가 대기 상태가 되면 다른 커널 스레드가 작업을 대신해 사용자 레벨 스레드 보다 효율적으로 작업을 처리한다.
- 커널 레벨 스레드에서 발생하는 문맥 교환에 따른 오버헤드를 가져 속도가 저하된다.
- 속도가 중요할 때는 사용자 레벨 스레드로 작동하고 보안과 커널 기능이 중요할 때는 커널 레벨 스레드로 작동한다.
- Golang은 이를 지원함으로써 효율적인 멀티 스레딩을 가능하게 하였다.
Green 스레드(M : 1)
- 자바 1.2 이전 버전에서 사용
- Many-to-One Model 또는 Many-to-Many Model 에서의 유저 스레드 들을 그린 스레드라고 한다.
- OS와는 독립적으로 유저 레벨에서 스케줄링되는 스레드
※ 일반적으로 다른 수식어 없이 '스레드'라고 한다면 보통은 OS 스레드를 말하거나 OS 스레드와 1 : 1로 매핑되는 유저 스레드라고 이해하면 될 것 같다.
※ OS와는 별개로 유저 레벨에서 자체적으로 관리되고 스케줄링되는 스레드는 유저 스레드 혹은 그린 스레드라고 불린다고 생각하면 될 것 같다.
이 글은 아래 영상을 보고 정리하는 글 입니다.
https://www.youtube.com/watch?v=vorIqiLM7jc
※ 스레드를 많이 쓸수록 항상 성능이 좋아질까요?
기본적으로 tomcat 스레드가 256개 정도, gc 스레드가 10개 정도 떠서 아무것도 하지 않아도 대충 250 ~ 300개의 스레드가 뜬다.
보통 대기업의 서비스 환경에서 4코어 또는 8코어에 16기가 정도 메모리를 사용하는데도 서비스가 가능하다는 것은 스레드의 중요성을 알 수 있다.
스레드의 갯수를 올리다보면 성능이 좋아지기는 하는데 어느 지점부터는 거의 그대로거나 심지어는 성능이 내려갈 때도 있다.
이것은 컨텍스트 스위칭 비용이 비싸다고 주장하는 사람들의 근거가 된다.
'Development > OS' 카테고리의 다른 글
프로그램, 프로세스, 스레드, 멀티 태스킹, 멀티 스레드, 멀티 프로세싱, 멀티 코어 (0) | 2023.02.11 |
---|