[운영체제/OS] 3. 쓰레드 Thread

✍︎ 운영체제 내부구조 및 설계원리 제8판 (Operating Systems Internals and Design Principles) 을 정리하는 글입니다.

💪 이 장의 목적

  • 프로세스와 쓰레드의 차이를 이해할 수 있다.
  • 쓰레드와 관련된 기본 설계 이슈를 설명할 수 있다.
  • 사용자 수준의 쓰레드와 커널 수준의 쓰레드의 차이를 설명할 수 있다.

인덱스

  1. 쓰레드(Thread)란?

  2. 쓰레드의 상태

  3. 쓰레드의 유형

쓰레드(Thread)란?

프로세스 내 실행 단위, 실행을 위해 스케줄링 될 수 있는 프로세스내의 개체

프로세스와 쓰레드의 차이

프로세스는 다음과 같은 특징이 있다.

  • 자원 소유권이 있다.

    • 프로세스는 자신의 이미지를 위한 가상주소공간을 포함한다.
    • 운영체제는 자원들에 대한 제어와 소유권을 프로세스에 할당하고, 보호기능을 수행하여 프로세스 간 불필요한 자원 간섭을 방지한다.
  • 프로세스는 수행상태, 디스패칭 우선순위를 가진, 운영체제에 의해 스케줄되고 디스패치되는 개체이다.

두 특성은 상호 독립적이기 때문에 구별해야할 필요가 있다.

1번 특성에 따라, 자원 소유권 단위는 프로세스(process) 또는 태스크(task)
2번 특성에 따라, 디스패칭의 단위는 쓰레드(thread) 또는 경량 프로세스(lightweight process)

쓰레드를 지원하는 운영체제에서는 스케줄링과 디스패칭이 쓰레드를 기반으로 이뤄지기 때문에 수행에 관련된 대부분의 상태 정보는 쓰레드 수준의 자료구조에 의해 유지된다. 하지만 몇 가지 작업들은 프로세스 내 모든 쓰레드에 영향을 미치기 때문에 운영체제는 프로세스 수준에서 이런 경우를 관리할 수 있어야 한다.

예시
- 프로세스의 보류(suspension) 상태의 경우, 프로세스 내 모든 쓰레드는 같은 주소 공간을 공유하기 때문에 모든 쓰레드가 보류 상태로 전이된다.
- 한 프로세스 종료 시 해당 프로세스 내 모든 쓰레드 종료

멀티쓰레딩 Multithreading

운영체제가 하나의 프로세스 내 여러 개의 쓰레드를 지원하는 기능

예시

{ - 쓰레드의 수행 상태
- 수행 중이지 않을 때 저장되어있는 수행 문맥
- 수행 스택
- 지역변수 저장을 위한 각 쓰레드의 정적 저장소
- 프로세스의 메모리 및 자원 << 프로세스 내 모든 쓰레드에 의해 공유됨 }
하나 이상의 쓰레드 프로세스

쓰레드프로세스모델

  • 단일 쓰레드 접근 방법(single-threaded approach)에서는 thread의 개념이 뚜렷하게 보이지 않는다.
  • 멀티 쓰레드 프로세스 모델

    • 각 쓰레드마다 별도의 스택이 있고, 별도의 제어블록이 있다. 제어블록 = {레지스터 값, 우선순위, 그외 쓰레드 관련 상태 정보}
    • 프로세스 상태와 자원은 프로세스 내 쓰레드들에 의해 공유된다.
    • 쓰레드들은 같은 주소공간 내에 있으며 동일 데이터에 접근한다.

성능 측면에서 쓰레드의 장점

  1. 새로운 프로세스를 생성하는데에 소요되는 시간보다 기존 프로세스 내에서 새로운 쓰레드를 생성하는데에 소요되는 시간이 더 짧다.
  2. 쓰레드 종료 시간이 프로세스 종료 시간보다 짧다.
  3. 프로세스 교환보다 같은 프로세스 내 두 쓰레드 사이의 교환이 더 효율적이다.
  4. 같은 프로세스 내 쓰레드들은 효율적 통신이 가능하다
    ∵ 메모리 및 파일을 공유하기 때문에 커널을 호출하지 않고도 서로 통신할 수 있기 때문이다.

따라서, 연관된 수행 단위의 집합으로 구현되어야 하는 응용/기능은 독립 프로세스로 구현하는 것보다 쓰레드 모음으로 구현하는 것이 훨씬 효율적이다. ex) 파일 서버

또한 논리적으로 여러 다른 기능을 수행하는 특정 프로그램의 구조를 단순화할 수 있기 때문에, 단일처리기에서도 쓰레드 구조는 유용하다.

단일 사용자 멀티 프로세싱 시스템에서의 적용 예시

  1. 전면(foreground) 작업과 후면(background) 작업
    ex) spreadsheet 수정 작업

    Thread 1 Thread 2
    - spreadsheet 메뉴 보여주기
    - 사용자 입력 받기
    - 명령 수행 후 spreadsheet 갱신하기

    👉 이를 통해 이전 명령 완료 전 다음 명령을 수행할 수 있어 응용 프로그램의 수행 속도를 향상시킬 수 있다.

  2. 비동기(asynchronous) 처리
    ex) 1분 마다 RAM(메모리) 버퍼 내용을 디스크(보조기억저장장치)에 기록하는 워드 프로세서 설계 시,
    쓰레드는 주기적인 백업을 담당하며 OS를 통해 직접 자신을 스케줄 한다.
  3. 빠른 수행
    멀티 프로세서 시스템에서 한 프로세스 내의 여러 쓰레드들은 실제로 동시에 수행이 가능하다.
    ∴ 한 쓰레드가 특정 데이터의 입출력 작업으로 block 되어도 다른 쓰레드가 수행될 수 있다.
  4. 모듈 프로그램 구조

쓰레드의 상태

쓰레드도 수행 상태를 가지며 서로 동기화 될 수 있다.

주요 상태

  • 수행, 준비, 블록

4가지 쓰레드 연산

  1. 생성 Spawn

    • 프로세스가 생성될 때 쓰레드도 같이 생성됨
    • 쓰레드는 프로세스 내에서 다른 쓰레드 생성 가능
    • 새로운 쓰레드는 고유한 레지스터 문맥(context)과 스택 공간을 가지며, 생성된 다음 준비 queue에 놓인다.
  2. 블록 Block

    • 쓰레드가 어떤 사건을 기다려야 할 때, 사용자 레지스터, program counter, stack pointer 등 저장
    • 처리기는 동일 프로세스 내 또는 다른 프로세스 내 쓰레드들 중에 준비 상태의 쓰레드를 수행한다.
  3. 비블록 Unblock

    • 쓰레드가 기다리던 사건이 발생했을 때
  4. 종료 Finish

    • 쓰레드 작업 종료 시 레지스터 문맥과 스택 해제

단일 처리기상에서 멀티쓰레딩의 예

☝️ 단일 처리기에서는 멀티 프로그래밍을 이용해 멀티 쓰레딩을 구현할 수 있다. 즉, 여러 프로세스 내 여러 쓰레드들이 번갈아 가며 수행될 수 있다.

쓰레드 동기화

프로세스 내 모든 쓰레드는 자원을 공유한다. 따라서 하나의 쓰레드가 자원을 변경하는 경우 같은 프로세스 내의 쓰레드에게 영향을 미치기 때문에 쓰레드들의 상호 간섭을 막고, 자료구조 손상 방지를 위해 동기화가 필요하다.

쓰레드의 유형

✔️ 사용자 수준 쓰레드 User-level Thread

사용자 수준 쓰레드

  • 쓰레드는 모두 사용자 공간에 있다는 것을 위의 그림을 통해 알 수 있다. 따라서 쓰레드와 관련된 모든 일은 사용자 공간에서 이뤄지기 때문에 커널은 쓰레드의 존재조차 알지 못한다.
  • 쓰레드 라이브러리를 통해 구현된다. ex) 새로운 쓰레드는 쓰레드 라이브러리 내 생성 유틸리티(spawn utility)를 통해 생성됨
  • 제어가 쓰레드 라이브러리로 넘어갈 때에는 현 쓰레드의 context가 저장되고, 제어가 어떤 쓰레드로 넘어갈 때에는 해당 쓰레드의 문맥이 복구 된다. * 문맥(context): 사용자 레지스터 내용, pc, stack pointer 등으로 구성
  • 커널은 스케줄링은 프로세스 단위로 한다.

👇 아래 그림, 상태 전이도의 설명이다. 쓰레드2가 프로세스B를 블록시키는 시스템 호출을 수행하면 제어가 커널로 넘어간다. 커널은 프로세스B를 블록 상태에 놓고 입출력 작업을 시작한다. 이때 다른 프로세스로 제어가 넘어간다(프로세스가 교환된다).

이때 프로세스B의 쓰레드2의 상태는 여전히 ‘수행’인 것을 확인할 수 있다. 실제로 수행 중은 아니지만 커널이 프로세스 단위로 스케줄링을 하기 때문에 위와 같은 상태가 가능하다. 이때 쓰레드의 상태는 쓰레드 라이브러리가 관리한다.

예시

장점

  • 프로세스는 쓰레드 관리를 위해 커널모드로 전환될 필요가 없다. 모드 전환 시의 오버헤드 절감
    ∵ 쓰레드 관리를 위한 자원이 모두 사용자 주소 공간에 있기 때문이다.
  • 각각의 응용 프로그램에 맞는 스케줄링을 구성할 수 있다.
    ∵ 각각의 응용 프로그램에 가장 효율적인 스케줄링 알고리즘은 다를 수 있기 때문이다. 따라서 운영체제 스케줄러에 영향을 주지 않고 각각의 스케줄링 알고리즘을 구성할 수 있다.
  • 이식성이 높다. 어떤 운영체제에서도 적용 가능
    ∵ 기본 커널을 변경할 필요가 없기 때문이다.

단점

  • 일반적인 os에서 대부분의 시스템 호출은 해당 쓰레드를 블록시킬 뿐만 아니라 같은 프로세스 내 모든 쓰레드들도 블록시킨다.
  • 커널은 프로세스 단위로 스케줄링을 진행하기 때문에 단일 프로세스 내에서 하나의 쓰레드만 수행가능하다.
    → 멀티 프로세싱의 장점을 살릴 수 없다.
    → 확장이 어렵다.
    → 다중 처리 불가

✔️ 커널 수준 쓰레드 Kernel-level Thread

커널 수준 쓰레드

  • Kernel supported thread, lightweight process라고도 불린다.
  • 쓰레드 관련 작업이 모두 커널 공간에서 이뤄진다.
  • 커널은 쓰레드를 기반으로 스케줄링한다. << 사용자 수준 쓰레드의 단점 극복

장점

  • 같은 프로세스 내 여러 쓰레드 동시 스케줄 가능
  • 한 프로세스의 쓰레드가 블록되면 같은 프로세스의 다른 쓰레드 스케줄 가능

단점

  • 같은 프로세스 내 다른 쓰레드로의 제어 이동 시, 커널 모드로의 전환이 필요하다. ∴ 오버헤드 발생
속도 단일 쓰레드 프로세스 <<<<< KLT 멀티 쓰레드 < ULT 멀티 쓰레드

📍 커널 수준 멀티 쓰레드에서 사용자 수준 멀티 스레드 사이의 속도 향상 실현 여부는 응용 특성에 달려 있어 항상 보장되는 것이 아니다.

✔️ 혼합/결합된 접근 방법

혼합/결합

  • 쓰레드의 생성은 완전히 사용자 공간에서 이뤄진다.
  • 스케줄링 및 동기화도 대부분 사용자 공간에서 이뤄진다.
  • ULT들은 ULT의 수와 같거나 적은 KLT에 사상된다. if ULT의 개수가 n, n >= KLT의 개수

장점

  • 한 응용 프로그램의 쓰레드들이 다수의 처리기에서 병렬 수행이 가능하다.
  • 블록형 시스템 호출이 전체 프로세스를 블록시키지 않는다.
  • 적절한 결합 방법이 고안/설계될 경우, ULT와 KLT 각각의 방식에서의 장점들을 모두 살릴 수 있다.

Hi! I'm @Yeseul Lee
Passionate for what I love

GitHubLinkedIn