Computer Science/Operating System

[운영체제] Thread란?

정석이 2023. 3. 5. 23:58

 

✔ 정의

스레드는 CPU 이용의 가장 작은 단위이다.

 

 

구성

  • 스레드 ID
  • 프로그램 카운터 (PC)
  • 레지스터 집합
  • 스택

 

같은 프로세스에 속한 스레드들은 코드 섹션, 데이터 섹션, OS 리소스같은 운영체제 자원들을 공유한다.

 

프로세스가 멀티 스레드를 갖게 되면, 한 번에 한 개 이상의 task를 수행할 수 있게 된다.

 

단일 스레드 프로세스, 멀티 스레드 프로세스

 

 

대부분의 현대 운영체제는 한 프로세스가 다중 스레드를 가진다.

 

 

 

생긴 이유

하나의 응용 프로그램이 여러 개의 비슷한 작업을 처리해야 할 때 단일 스레드 프로세스의 경우 한 번에 하나의 클라이언트만 처리할 수 있어 시간이 오래걸린다.

 

 

그래서 보통 서비스 요청당 별도의 프로세스를 만드는데 프로세스를 만드는 작업은 많은 시간과 리소스가 필요하다.

 

이 때 새 프로세스가 기존 프로세스와 하는 일이 동일하다면 기존 프로세스 내부에 여러 개의 스레드를 만드는 것이 효율적이다.

 

 

 

장점

  • 응답성(Responsiveness)
    • 응용 프로그램의 일부분이 block되거나 긴 작업을 수행하더라도 나머지 스레드들을 통해 프로그램의 수행이 계속될 수 있으므로 사용자에 대한 응답성을 증가시킴

 

  • 자원 공유(Resource sharing)
    • 프로세스는 shared memory와 message passing을 통해 자원을 공유할 수 있지만
    • 스레드는 자동으로 그들이 속한 프로세스의 자원들과 메모리를 공유한다.

 

  • 경제성(Economy)
    • 스레드는 자신이 속한 프로세스의 자원들을 공유하므로 프로세스보다 스레드를 생성하고 context switch하는 것이 더욱 경제적이다.
    • 또한 프로세스보다 스레드 사이에서 context switch가 더 빠르다.

 

  • 규모 적응성(Scalability)
    • 단일 스레드 프로세스는 한번에 하나밖에 못돌리는데
    • 멀티 프로세서 구조에서 각각의 스레드는 여러 프로세서에 병렬로 수행될 수 있다.

 

 

✔ Multicore Programming

Multicore

컴퓨팅 시스템이 발전하면서 단일 컴퓨팅 칩에 여러 컴퓨팅 코어를 배치할 수 있게 되었다.

각 코어는 운영체제에 별도의 CPU로 보이게 되는데, 이런 시스템을 다중 코어(Multicore)라고 한다.

 

 

 

이런 다중 코어 시스템상에서는 시스템이 개별 스레드를 각 코어에 배치할 수 있기 때문에 스레드들이 병렬적으로 실행된다.

 

 

 

 

위 그림은 단일 코어 시스템에서의 동시 실행을 나타낸 것이다. 스레드를 교차 시켜 실행한다.

 

 

 

 

 

얘는 멀티코어 시스템에서의 병렬 실행이다.

 

 

 

 

✔ 병렬 실행 타입

 

 

 

data 병렬 실행

  • 동일한 데이터의 부분집합을 다수의 계산 코어에 분배한 뒤 각 코어에서 동일한 연산을 실행
  • 예를 들어 듀얼 코어라면 N개의 데이터에 대해 하나는 0~n/2까지, 다른 하나는 n/2+1 ~ n까지 각 코어에서 병렬로 처리하는 것

 

task 병렬 실행

  • 테스크(스레드)를 다수의 코어에 분배
  • 각 스레드는 고유의 연산을 실행

 

 

✔ Multithread Model

스레드는 사용자 스레드(user threads)와 커널 스레드(kernel threads)로 나뉜다.

 

 

 

 

사용자 스레드

  • 유저 모드에서 사용하는 스레드로, 개발자가 라이브러리를 사용해 직접 만드는 스레드이다.
    • User level의 thread library를 통해 구현된다.
  • 운영체제는 커널 모드에서 프로세스만 볼 수 있고 프로세스가 유저 모드에서 각 스레드들을 보고 있는 구조이다.
    • 그래서 하나의 스레드가 중단되면 그냥 프로세스 자체를 대기 상태로 바꾸므로 다른 스레드도 같이 중단된다.
  • user thread는 kernel thread와 매핑이 되어야만 프로세서를 사용할 수 있다.
    • kernel thread가 CPU 스케줄링의 단위가 된다.
  • Green thread라고도 불린다.

 

커널 스레드

  • 커널 모드에서 사용하는 스레드
  • 운영체제에 의해 직접 지원되고 관리됨
    • 그래서 하나의 스레드가 중단되어도 커널이 나머지 스레드를 계속 실행된다.
    • 멀티 프로세싱 환경에서 스레드들을 각각 다른 프로세서에 할당할 수 있다.
  • 단점은 스케줄링이나 동기화를 위해 system call을 하는 과정에서 오버헤드가 발생한다.
  • native thread라고도 불린다.

 

 

다대일 모델(Many-to-One)

 

 

많은 사용자 스레드를 하나의 커널 스레드로 관리한다.

스레드 관리가 사용자 공간의 스레드 라이브러리에 의해 행해지므로 효율적이다.

 

하지만 한 스레드가 block형 system call을 할 경우, 전제 프로세스가 block되는 등 다중 처리 코어의 이점을 살릴 수 없어 이 모델을 사용중인 시스템은 거의 존재하지 않는다.

 

 

일대일 모델(One-to-One)

 

 

 

일대일 모델은 각 사용자 스레드가 각각 하나의 커널 스레드로 매핑된다.

다대일처럼 한 스레드가 block형 시스템 콜을 해도 나머지가 실행될 수 있으므로 병렬성을 제공한다.

 

단점은 사용자 스레드를 만들려면 해당 커널 스레드를 만들어야 하며, 많은 수의 커널 스레드가 시스템 성능에 부담을 줄 수 있는 점이다.

 

Linux, Windows 운영체제가 이에 해당한다.

 

 

다대다 모델(Many-to-Many)

 

 

 

다대다 모델은 여러 개의 사용자 스레드를 그보다 작거나 같은 수의 커널 스레드로 매핑한다.

이 모델은 스레드 수가 맞지 않아도 되는 병렬성을 제공한다.

 

그러나 구현이 매우 어려워서 대부분의 운영체제는 일대일 모델을 사용한다.

 

 

 

✔ 스레드 라이브러리

스레드 라이브러리는 프로그래머에게 스레드를 생성하고 관리할 수 있는 API를 제공한다.

 

구현 방법

  • 커널의 지원 없이 완전히 사용자 공간에서만 라이브러리를 제공하는 방법
  • 운영체제에 의해 지원되는 커널 수준 라이브러리를 구현하는 방법

 

 

현재는 POSIX, Windows, Java 세 종류의 스레드 라이브러리가 주로 사용된다.

 

 

 

✔ 스레딩(Threading)

비동기 스레딩 (Synchronous)

부모가 자식 스레드를 생성한 후 부모는 자신의 실행을 재개해 부모와 자식 스레드가 독립적으로 병행하게 실행된다.

스레드가 독립적이므로 스레드 사이의 데이터 공유가 거의 없다.

 

 

동기 스레딩 (Asynchronous)

부모 스레드가 하나 이상의 자식 스레드를 생성하고 자식 스레드가 모두 종료될 때까지 기다렸다가 자신의 실행을 재개한다.

보통 동기 스레딩은 스레드 사이의 상당한 양의 데이터 공유를 수반한다.

 

 

 

 

✔ 암묵적 스레딩

다중 코어 처리의 성장에 따라 수백, 수천 개의 스레드를 가진 어플리케이션이 등장하게 되었다.

 

스레딩의 생성과 관리 책음을 프로그래머로부터 컴파일러와 실행 시간 라이브러리에게 넘겨주는 것이 암묵적 스레딩이다.

이를 사용하면 멀티 스레딩을 효율적으로 활용할 수 있다.

 

개발자는 병렬 작업만 실행하면 되고 세부 사항은 라이브러리가 결정하는 것이다.

 

 

 

 

✔ 스레드 풀(Thread Pool)

  • 프로세스를 시작할 때 일정 수의 스레드들을 미리 풀로 만들어두는 것

 

웹 서버는 요청을 받을 때마다 새로운 스레드를 만들어준다.

 

그러나 이렇게 하면

  • 서비스할 때마다 스레드를 생성 시간이 소요되고
  • 무한정 스레드를 만들게 되면 자원이 고갈된다.

 

 

그래서 모든 요청마다 새 스레드를 만들어서 서비스해주려면 최대 스레드 수를 정해야 한다.

 

그래서 스레드 풀을 사용하여 일정 수의 스레드들을 미리 만들어놓고 그 안에 있는 스레드를 사용한다.

 

 

장점

  • 기존 스레드를 서비스하므로 빠르다
  • 존재할 스레드 개수에 제한을 두어 많은 수의 스레드를 병렬 처리할 수 없는 시스템에 도움이 된다.
  • 테스크를 생성하는 방법을 분리하여 테스크의 실행을 유연하게 할 수 있다.