001 Thread

스레드 종류 - 하드웨어 스레드, OS 스레드, 네이티브 스레드, 커널 스레드, 유저 스레드, 그린 스레드 #

우리가 작성한 프로그램의 동작방식 #

  • 하드웨어
  • OS Kernel
  • User Program : 운영체제를 통해 하드웨어를 사용 img.png

Hardware thread #

  • 코어(core)의 고민 : 메모리에서 데이터를 기다리는 시간이 꽤 오래 걸린다.
    • 코어에서 프로그램이 실행될때 각종 연산 작업이 있을테고, 이를 위해 메모리에 접근하는 작업들이 있다. 이 코어에서 실행되는 연산 작업에 비해 메모리에서 데이터를 기다리는 시간이 더 오래 걸린다. 이는 코어를 낭비하고있다는 말과 같다.
    • 메모리를 기다리는 동안 다른 쓰레드를 실행하는건 어떨까?
    • 예시) 코어 -> Computing 작업 -> 메모리에 접근하여 데이터 처리 -> Computing 작업 -> 메모리에 접근…
      • 코어가 쉬고있을때마다 코어를 낭비하는 것과 같다.
    • 이를 해결하기 위해, 메모리에 접근하는 동안 독립적으로 또다른 무언가를 실행하면 어떨까?
    • 1개의 코어에서 2개의 쓰레드를 실행하는 것 -> 이 각각의 쓰레드를 Hardware Thread라고 한다.
      • 이를 인텔의 Hyper-threading 이라고 한다.
        • 물리적인 코어마다 하드웨어 스레드가 2개다. img_4.png
      • Hardware Thread : OS 관점에서는 가상의 코어
      • 싱글코어 CPU에 하드웨어 스레드가 2개라면, OS는 이 CPU를 듀얼 코어로 인식하고, 이에 맞춰서 OS 레벨의 스레드들을 스케줄링한다.

OS Thread #

img_5.png

  • OS Kernel 영역에 해당되는 부분
  • 커널(kernel)
    • 운영체제의 핵심
    • 시스템의 전반을 관리/감독하는 역할
    • 하드웨어와 관련된 작업을 직접 수행
  • OS Thread
    • OS 커널 레벨에서 생성되고 관리되는 스레드
    • CPU에서 실제로 실행되는 단위, CPU 스케줄링의 단위
    • OS 스레드들의 컨텍스트 스위칭은 커널이 개입 -> 비용 발생
    • 사용자 코드와 커널 모드 모두 OS 스레드에서 실행된다. img_6.png
      • 우리가 작성한 코드가 OS 스레드로 실행되고, system call을 사용하면 커널 모드로 전환되고, 여기서 커널 코드가 실행되는데 이도 OS 스레드에서 실행된다.
    • native 스레드, 커널 스레드, 커널-레벨 스레드, OS-레벨 스레드 라고 불리기도한다.
    • OS 스레드 8개가 하이퍼 스레딩이 적용된 인텔 듀어코어 위에서 동작한다면 OS 스레드들을 어떻게 코어에 균등하게 할당할까? img_1.png img_7.png
      • 코어마다 하드웨어 쓰레드가 2개씩 있고, OS 입장에서는 하드웨어 쓰레드 각각이 코어로 인식되고, 이 코어 당 쓰레드 2개씩 할당한다.

User Thread #

  • 유저-레벨 쓰레드라고 불리기도한다.
  • 스레드 개념을 프로그래밍 레벨에서 추상화 한것이다.
    Thread thread = new Thread();
    thread.start();
    
    img_2.png
  • 자바에서 제공하는 Thread라는 Class 사용 - start()의 구현부에서 start0() 메서드를 호출하는데, 이는 JNI라는 기술을 통해 OS SystemCall을 호출한다.
    • 리눅스라면 clone 이라는 system call 호출 -> 리눅스에서는 OS 레벨의 쓰레드를 1개 생성하게된다. 이 쓰레드는 User-level의 쓰레드와 연결이 된다.
  • 유저 스레드가 CPU에서 실행되려면 OS 스레드와 반드시 연결되어야한다.
    • (= 기본적 CPU에서 실행되는 단위는 커널 스레드이기 때문! 따라서 유저 스레드는 반드시 커널 스레드와 연결이 되어야 하고, 그 후에 커널 스레드가 CPU에서 실행이 된다.) img_8.png
  • 유저 스레드와 OS 쓰레드를 어떻게 연결할까?
      1. One-to-One model : start() 하는 순간, OS 레벨의 쓰레드를 생성하여 1:1로 연결한다.
      • 쓰레드 관리를 OS에 위임한다. (스케줄링 포함)
      • 스케줄링도 커널이 수행한다.
      • CPU가 만약에 멀티코어를 가진다고 해도, 이 멀티코어에 OS 쓰레드를 잘 분배하여 동작시키면, 1:1로 분배되는 유저 쓰레드도 멀티코어를 잘 활용하게된다.
      • 한 쓰레드가 block이 되도, 나머지 쓰레드에는 영향없이 잘 동작한다.
      • race condition 발생 가능성 있음
      1. 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된다.
      1. Many-to-Many model : User Thread, OS Thread 가 모두 N:N으로 연결된다.
      • 위 1), 2) 방법의 장점을 살린 방법
      • 구현이 복잡하다. img_3.png
  • 기술 문서에서는 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 커널의 역할을 수행하는 스레드