04. 스레드와 멀티스레딩

하이솝·2026년 4월 1일

운영체제

목록 보기
4/9

강의 목표

  • 프로세스의 문제점을 인식하고 스레드의 필요성과 개념을 이해한다.
  • 오늘날 운영체제의 실행 단위가 스레드임을 알고
    오늘날 운영체제는 스레드 단위로 스케줄함을 안다.
  • 스레드와 프로세스의 차이, 이들의 관계에 대해 이해한다.
  • 멀티스레드 샘플 코드를 통해 멀티스레드 응용프로그램의 작성 방법을 간단히 알고, 스레드의 생성 및 실행 과정을 이해한다.
  • 커널 레벨 스레드사용자 레벨 스레드의 차이점을 이해한다.
  • 멀티스레딩이 구현되는 3가지 방법에 대해 이해한다.

01. 프로세스의 문제점

다중 프로세스를 이용한 멀티태스킹 활용

  • 응용프로그램에서는 여러 프로세스를 생성하여 동시에 여러 작업 실행
  • 운영체제는 프로세스 스케줄링을 통해 프로세스를 번갈아 가면서 실행

프로세스를 실행 단위로 하는 멀티태스킹의 문제점


1.프로세스 생성의 큰 오버헤드

  • 프로세스를 위한 메모리 할당, 부모프로세스로부터 복사
  • PCB 생성, 매핑(페이지) 테이블 생성

2. 프로세스 컨텍스트 스위칭의 큰 오버헤드

  • CPU 레지스터들을 컨텍스트로 PCB에 저장,
    새 프로세스 컨텍스트를 PCB에서 CPU로 옮기는 시간
  • CPU가 참고할 매핑 테이블의 교체 시간
  • CPU 캐시에 새 프로세스의 코드와 데이터가 채워지는 데에 걸리는 시간 등

3. 프로세스 사이 통신의 어려움

  • 프로세스가 다른 프로세스의 메모리에 접근 불가
  • 프로세스 사이의 통신을 위한 제 3의 방법 필요(Inter Process Communication)
  • 커널 메모리나 커널에 의해 마련된 메모리 공간을 통해 데이터 송수신
    신호, 소켓, 메시지 큐, 세마포, 공유메모리, 메모리 맵 파일 등
    이러한 방법들은 코딩이 어렵고, 실행 속도가 느리며, 운영체제 호환성 부족

프로세스 사이의 통신 방법

02. 스레드 개념

2.1 스레드의 출현 목적


프로세스를 실행 단위로 하는 멀티태스킹

  • 커널에 많은 시간/공간 부담 → 시스템 전체 속도 저하

스레드 출현 - 효율적인 새로운 실행 단위의 필요

프로세스보다 크기가 작아서 프로세스보다
생성 및 소멸이 빠르고, 컨텍스트 스위칭이 빠르며, 통신이 빠른 실행 단위

가벼운 프로세스(Light-Weight Process, LWP)라고도 부름

2.2 스레드 개념


스레드는 실행 단위이며 스케줄링 단위

스레드는

  • 응용프로그램 개발자에게는 작업을 만드는 단위
  • 운영체제에게 실행 단위이며, CPU를 할당하는 스케줄링 단위
  • 코드, 데이터, 힙, 스택을 가진 실체
  • 정보를 저장하는 구조체 TCB(Thread Control Block)이 있음
    TCB는 스레드 엔터티(thread entity) 또는
    스케줄링 엔터티(scheduling entity)라고도 부름

프로세스는 스레드들의 컨테이너

  • 프로세스 개념이 스레드들의 컨테이너 역할로 수정됨
  • 프로세스는 반드시 1개 이상의 스레드로 구성
    메인(main) 스레드: 프로세스가 생성될 때 운영체제에 의해 자동으로 생성되는 1개의 스레드
    프로세스는 회사, 스레드는 직원

    프로세스와 스레드 관리 구성

프로세스는 스레드들의 공유 공간 제공

  • 모든 스레드는 프로세스의 주소 공간을 나누어 사용
  • 공유되는 공간을 사용하면 스레드 사이의 통신 용이

스레드가 실행할 작업은 함수로 작성한다.

  • 응용프로그램은 스레드가 실행할 작업을 함수로 작성

  • 스레드를 만들어줄 것을 운영체제에 요청하면 스레드 생성
    운영체제는 TCB 생성, 함수의 주소를 스레드 시작 주소로 TCB에 등록
    스레드 생성이란, 곧 TCB 생성

  • 스레드는 운영체제 뿐만 아니라 스레드 라이브러리에 의해 구현되기도 한다.
    스레드 라이브러리에 의해 구현되는 경우, 스레드를 다루지 않은 운영체제에서도 멀티스레딩 응용프로그램을 작성할 수 있음

  • 운영체제는 TCB 리스트로 스레드 관리
    스레드 스케줄: TCB 중에서 하나 선택, 스레드 단위로 스케줄
    TCB에 기록된 스레드의 시작 주소를 CPU에 옮기면 실행 시작됨


스레드와 프로세스의 생명

  • 스레드로 만든 함수가 종료하면 스레드 종료
  • 스레드가 종료하면 TCB 등 스레드 관련 정보 모두 제거
  • 프로세스에 속한 모든 스레드가 종료될 때, 프로세스 종료

2.3 스레드 만들기 맛보기


프로그램 코드

#include <pthread.h> // pthread 라이브러리를 사용하기 위해 필요한 헤더 파일
#include <stdio.h>
#include <stdlib.h>

void* calcThread(void *param); // 스레드로 작동할 코드(함수)
int sum = 0; // main 스레드와 calcThread가 공유하는 전역 변수

int main() {
        pthread_t tid; //  스레드의 id를 저장할 정수형 변수
        pthread_attr_t attr; // 스레드 정보를 담을 구조체

        pthread_attr_init(&attr); // 디폴트 값으로 attr 초기화
        pthread_create(&tid, &attr, calcThread, "100"); // calcThread 스레드 생성
        // 생성된 calcThread 스레드는 커널에 의해 언젠가 스케줄되어 실행

        pthread_join(tid, NULL); // tid 번호의 스레드 종료를 기다림
        printf("calcThread 스레드가 종료하였습니다.\n");
        printf("sum = %d\n", sum);
}

void* calcThread(void *param) { // param을 통해 "100"을 전달 받음
        printf("calcThread 스레드가 실행을 시작합니다.\n");
        int to =  atoi(param); // to = 100
        int i;

        for(i=1; i<=to; i++) // 1에서 to까지 합 계산
                sum += i; // 전역 변수 sum에 저장
}

실행 과정

2.4 멀티스레드 응용프로그램 사례

2.5 멀티스레딩 분석

함수는 다른 함수에 의해 호출되어 실행되지만,
스레드 함수의 코드는 CPU가 바로 실행하도록 커널에 의해 직접 제어된다.


TIP. 멀티스레딩과 concurrency, parallelism

동시성(concurrency)

  • 1개의 CPU에서 2개 이상의 스레드가 동시에 실행 중인 상태
    스레드가 입출력으로 실행이 중단될 때 다른 스레드 실행
    타임 슬라이스(시분할) 단위로 CPU를 사용하도록 번갈아 스레드 실행

병렬성(parallelism)

  • 2개 이상의 스레드가 다른 CPU에서 같은 시간에 동시 실행

03. 스레드 주소 공간과 컨텍스트

3.1 스레드 주소 공간

스레드가 실행 중에 사용하는 메모리 공간으로
스레드의 코드, 데이터, 힙, 스택 영역이며,
이들은 모두 프로세스의 주소 공간에 형성된다.


스레드 주소 공간은 프로세스 주소 공간 내에서 사적 공간과 공유 공간으로 구분됨

  • 스레드 사적 공간
    스레드 스택
    스레드 로컬 스토리지(Thread Local Storage, TLS)
    운영체제에 따라 다르지만, 대체로 힙이나 스택 영역에 할당됨

  • 스레드 사이의 공유 공간
    프로세스의 코드(스레드 코드 포함)/데이터/힙 공간


스레드 주소 공간에 대한 설명

스레드 코드 영역

  • 스레드가 실행할 작업의 함수, 프로세스의 코드 영역 사용
  • 스레드는 프로세스 코드 영역에 있는 다른 함수 호출 가능

스레드 데이터 영역

  • 프로세스의 데이터 영역 공유
  • 프로세스에 선언된 모든 전역 변수들

스레드 힙

  • 스레드가 동적 할당받는 공간, 프로세스 힙 공간 공유
  • 스레드에서 malloc()를 호출하면 프로세스의 힙 공간에서 메모리 할당

스레드 스택

  • 스레드가 생성될 때,
    프로세스에게 할당된 스택 공간에 사용자 스택 할당
    (운영체제마다 다름, 예) 8MB)

    커널 공간에 스레드마다 커널 스택 할당(운영체제마다 다름, 예) 8KB, 12KB)
  • 스레드가 사용자/커널 모드에서 사용될 때 각각 사용자/커널 스택 활용
  • 스레드 종료 시, 스레드가 할당 받은 사용자/커널 스택 모두 반환

스레드 로컬 스토리지(Thread Local Storage, TLS)

  • 스레드마다 안전하게 다루고자 하는 데이터를 저장하기 위한 별도의 영역
    프로세스의 데이터 영역은 모든 스레드들의 공용 공간이기 때문

  • 스레드가 자신만 사용할 변수들을 선언할 수 있는 영역
    지역 변수와는 달리, TLS 변수는 스레드가 어떤 함수에서든 접근이 가능함
    (해당 스레드 한정, 전역 변수처럼 활용 가능)

    운영체제마다 다르지만, 대체로 프로세스의 힙이나 스택 영역에 할당됨

3.2 스레드의 주소 공간 확인

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

void printsum(); // 모든 스레드에 의해 호출되는 함수
void* calcThread(void *param); // 스레드 코드(함수)

static __thread int tsum = 5; // 스레드 로컬 스토리지(TLS)에 tsum 변수 선언
int total = 0; // 프로세스의 전역 변수, 모든 스레드에 의해 공유

int main() {
        char *p[2] = {"100", "200"};
        int i;
        pthread_t tid[2]; // 스레드의 id를 저장할 정수 배열
        pthread_attr_t attr[2]; // 스레드 정보를 담을 구조체

        // 2개의 스레드 생성
        for(i=0; i<2; i++) {
                pthread_attr_init(&attr[i]);  // 구조체 초기화
                pthread_create(&tid[i], &attr[i], calcThread, p[i]); // 스레드 생성
                printf("calcThread 스레드가 생성되었습니다.\n");
        }

        // 2개 스레드의 종료를 기다린 후에 total 값 출력
        for(i=0; i<2; i++) {
                pthread_join(tid[i], NULL); // 스레드 tid[i]의 종료대기
                printf("calcThread 스레드가 종료하였습니다.\n");
        }
        printf("total = %d\n", total); // 2개 스레드의 합이 누적된 total 출력
        return 0;
}

void* calcThread(void *param) { // 스레드 코드
        printf("스레드 생성 초기 tsum = %d\n", tsum); // TLS 변수 tsum의 초기값 출력

        int i, sum = 0; // 지역 변수
        for(i=1; i<= atoi(param); i++) sum += i; // 1~param까지 더하기
       
        tsum = sum; // TLS 변수 tsum에 합 저장
        printsum();
        total+=sum; // 전역 변수 total에 합 누적
}

void printsum() { // 모든 스레드가 호출할 수 있는 공유 함수
        printf("계산 후 tsum = %d\n", tsum);
}


Q1. 이 프로그램이 실행되는 동안 총 몇개의 스레드가 실행되는가?
main() 스레드를 포함하여 총 3개의 스레드가 실행된다.

Q2. tsum은 무슨 변수라고 부르며, total 변수와의 차이점은 무엇인가?
TLS(Thread Local Storage) 변수.
모든 스레드가 공유하는 total 변수와는 다르게,
각 스레드의 독립적인 공간에 할당되는 변수이다.

3.3 스레드 상태와 스레드 운용(operation)


스레드 일생

  • 스레드는 생성, 실행, 중단, 실행, 소멸의 여러 상태를 거치면서 실행
  • 스레드 상태는 TCB에 저장
  • 스레드 상태
    준비 상태 (Ready) - 스케줄 되기를 기다리는 상태
    실행 상태 (Running) - 스레드가 CPU에 의해 실행 중인 상태
    대기 상태 (Blocked) - 스레드가 입출력을 요청하거나,
    sleep() 같은 시스템 호출로 인해 중단된 상태
    종료 상태 (Terminated) - 스레드가 종료한 상태

스레드 운용(operation)

응용프로그램이 스레드에 대해 할 수 있는 운용의 종류

스레드 생성

  • 프로세스가 생성되면 운영체제에 의해 자동으로 main 스레드 생성
  • 스레드는 스레드를 생성하는 시스템 호출이나
    라이브러리 함수를 호출하여 새 스레드 생성 가능
  • 스레드는 스레드에 의해 생성됨
  • 부모-자식 관계를 가짐
    종료를 부모에게 통보하지 않음
    자식 스레드에 대한 ID를 가지고 있어, 자식 스레드 제어가 가능함

스레드 종료

  • 프로세스 종료와 스레드 종료의 구분 필요
  • 프로세스 종료
    1) 프로세스에 속한 아무 스레드가 exit() 시스템 호출을 부르면
    프로세스 종료(모든 스레드 종료)
    2) 메인 스레드의 종료(C 프로그램의 main() 함수 종료) - 모든 스레드 종료
    3) 모든 스레드가 종료하면 프로세스 종료
  • 스레드 종료
    1) pthread_exit()와 같이 스레드만 종료하는 함수 호출 시
    해당 스레드만 종료
    2) main() 함수에서 pthread_exit()를 부르면 main() 스레드만 종료

main() 스레드에서 return이나 exit()를 호출하면 프로세스가 종료되지만, pthread_exit()를 호출하면 main() 스레드만 종료된다.

종료가 되면 TCB의 연결이 해제되며 TCB와 스레드 스택은 사라지지만,
스레드가 실행했던 코드는 그대로 존재한다.

  • 스레드 조인
    다른 스레드가 종료할 때 까지 대기
    주로 부모 스레드가 자식 스레드의 종료 대기

  • 스레드 양보
    스레드가 자발적으로 yield() 와 같은 함수 호출을 통해 스스로 실행을 중단하고 다른 스레드를 스케줄하도록 요청

3.4 스레드 컨텍스트와 스레드 제어 블록(TCB)


스레드 컨텍스트

  • 스레드가 현재 실행 중인 일체의 상황
  • CPU 레지스터 값들

스레드 컨텍스트 정보

  • PC 레지스터
    다음에 실행할 코드 주소

  • SP 레지스터
    실행 중인 함수의 스택 톱 주소

  • 상태 레지스터
    현재 CPU의 상태 정보

이러한 정보들이 컨텍스트 스위치 될 때 TCB에 저장이 됨


스레드 제어 블록(TCB, Thread Control Block)

  • 스레드를 실행 단위로 다루기 위해 스레드에 관한 정보를 담은 구조체
    스레드 엔터티(thread entity) 또는 스케줄링 엔터티(scheduling entity)

  • 커널 영역에 만들어지고 커널에 의해 관리됨
    스레드가 생성될 때 커널에 의해 만들어지고, 스레드 소멸되면 사라짐


준비 리스트와 블록 리스트

준비 리스트

  • 준비 상태에 있는 스레드들의 TCB를 연결하는 링크드 리스트
  • 스레드 스케줄링은 준비 리스트의 TCB 중 하나 선택

블록 리스트

  • 블록 상태에 있는 스레드들의 TCB를 연결하는 링크드 리스트

운영체제에게 스레드는 TCB이다

3.5 스레드 컨텍스트 스위칭


정의

스레드 스케줄링 후,
현재 실행중인 스레드를 중단시키고, 선택된 스레드에게 CPU 할당
현재 실행중인 스레드의 컨텍스트를 TCB에 저장 후,
선택된 스레드의 TCB에서 컨텍스트를 적재, CPU는 선택된 스레드 실행


스레드 스위칭이 발생하는 경우

시스템 호출이나 인터럽트 서비스 도중에 발생
1) 스레드가 자발적으로 다른 스레드에게 양보하는 경우(시스템 호출 내)

  • 스레드가 직접 yield() 시스템 호출을 불러 다른 스레드에게 양보
  • sleep()이나 wait() 등의 시스템 호출을 하는 경우

2) 스레드가 I/O 작업을 요청하는 시스템 호출 시 블록되는 경우(시스템 호출 내)

  • read(), sleep(), wait() 등 I/O가 발생하거나 대기할 수 밖에 없는 경우

3) 스레드의 타임 슬라이스를 소진한 경우(인터럽트 서비스 루틴 내)

  • 타이머 인터럽트에 의해 체크되어 진행

4) I/O 장치로부터 인터럽트가 걸린 경우(인터럽트 서비스 루틴 내)

  • 현재 실행중인 스레드보다 높은 순위의 스레드가 I/O 작업을 끝낸 경우

스레드 스위칭이 이루어지는 위치

  • 스레드가 시스템 호출을 하여, 커널이 시스템 호출을 처리하는 과정
  • 인터럽트가 발생하여 인터럽트 서비스 루틴이 실행되는 도중 커널 코드에서

스레드 스위칭 과정

1) CPU 레지스터 저장 및 복귀

  • 현재 실행 중인 스레드 A의 컨텍스트를 TCB-A에 저장
  • TBC-B에 저장된 스레드 B의 컨텍스트를 CPU에 적재
    CPU는 스레드 B가 이전에 중단된 위치에서 실행 재개 가능
    SP 레지스터를 복귀함으로서 자신의 이전 스택을 되찾게 됨
    스택에는 이전 중단될 때 실행하던
    함수의 매개변수나 지역변수들이 그대로 저장되어 있음

2) 커널 정보 수정

  • TCB-A와 TCB-B에 스레드 상태 정보와 CPU 사용 시간 등 수정
  • TCB-A를 준비 리스트나 블록 리스트로 옮김
  • TCB-B를 준비 리스트에서 분리

별도의 스케줄링 스레드는 존재하지 않으며,
스케줄링 코드가 존재하여 시스템 호출이나 인터럽트 과정에서 호출된다.

3.6 컨텍스트 스위칭의 오버헤드

컨텍스트 스위칭 작업은 모두 CPU 작업 → CPU 시간 소모
컨텍스트 스위칭의 시간을 최소화 할 필요가 있음


동일한 프로세스 내 다른 스레드로 스위칭하는 경우

  • 1) 컨텍스트 저장 및 복귀 시간
    현재 CPU의 상태를 스레드의 TCB에 저장하고, 새로 선택된 스레드의 TCB에 저장된 레지스터 값들을 CPU에 복귀하는 시간
  • 2) TCB 리스트 조작 시간
    스레드의 TCB를 준비 리스트나 블록 리스트 등으로 옮기는 시간
  • 3) 캐시 플러시 및 채우기 시간
    이 과정은 컨텍스트 스위칭 이후 새 스레드가 실행하는 동안 이루어지므로 컨텍스트 스위칭 시간에 포함시키지 않는다.

다른 프로세스의 스레드로 스위칭되는 경우

다른 프로세스로 교체되면, CPU가 실행하는 주소 공간이 바뀌는 큰 변화로 인해 추가적인 오버헤드가 발생

  • 1) 메모리 관련 오버헤드
    논리 주소를 물리 주소로 매핑하는 MMU(Memory Management Unit) 장치에서 매핑 테이블을 교체하는 시간
    새 프로세스의 TLB(Translation Look-aside Buffer)를 채우는 시간
  • 2) 추가적인 캐시 오버헤드
    프로세스가 바뀌기 때문에, 현재 CPU에 담긴 코드와 데이터를 무력화시킴
    새 프로세스의 스레드가 실행을 시작하면
    CPU 캐시 미스 발생 캐시가 채워지는 데 상당한 시간 소요
    (컨텍스트 스위칭 시간에 포함시키지 않음)

스레드 스위칭 오버헤드 줄이기

컨텍스트 스위칭은 CPU 시간이 소모되는 CPU 집중(CPU intensive) 작업

  • 프로세스를 특정 CPU 코어에 배치하여,
    CPU가 여러 프로세스에 걸쳐 스레드를 실행하지 않도록 함

  • CPU에 별도 레지스터 셋을 두어
    CPU의 레지스터들을 TCB에 저장하지 않는 방법을 사용하기도 함

04. 커널 레벨 스레드와 사용자 레벨 스레드

4.1 커널 레벨 스레드와 사용자 레벨 스레드

스레드는 스케줄링 주체에 따라 2종류로 구분됨

  • 커널 레벨 스레드(kernel-level thread)
    커널에 의해 스케줄링되는 스레드
  • 사용자 레벨 스레드(user-level thread)
    스레드 라이브러리에 의해 스케줄링되는 스레드

커널 레벨 스레드

  • 스레드에 대한 정보(TCB)는 커널 공간에 생성되며, 커널에 의해 소유됨
  • 응용프로그램이 시스템 호출을 통해 커널 레벨 스레드 생성
    시스템 호출을 통해서만 이 기능을 활용할 수 있음
  • 커널이 만들고, 커널에 의해 스케줄됨
  • 스레드 주소 공간(스레드 코드와 데이터): 사용자 공간에 존재
  • main 스레드는 커널 스레드
    커널이 응용프로그램을 적재하고 프로세스를 생성할 때
    자동으로 main 스레드 생성
    main 스레드의 TCB는 커널에 생성

순수 커널 레벨 스레드(pure kernel level thread)
부팅할 때부터 커널 공간에서 실행되도록 작성된 커널 레벨 스레드


사용자 레벨 스레드

  • 응용프로그램이 스레드 라이브러리 함수를 호출하여 사용자 레벨 스레드 생성
  • 스레드 라이브러리가 스레드 정보(U-TCB)를 사용자 공간에 생성하고 소유
    스레드 라이브러리는 사용자 공간에 존재
    커널은 사용자 레벨 스레드의 존재에 대해 알지 못함
  • 스레드 라이브러리에 의해 스케줄
  • 스레드 주소 공간(스레드 코드와 데이터): 사용자 공간에 존재

4.2 커널 레벨 스레드와 사용자 레벨 스레드 사례


순수 커널 레벨 스레드

  • 부팅 때부터 커널의 기능을 돕기 위해 만들어진 스레드
  • 커널 코드를 실행하는 커널 스레드
  • 스레드의 주소 공간은 모두 커널 공간에 형성
  • 커널 모드에서 작동, 사용자 모드에서 실행되는 일 없음


개요: 프로세스 2개, 커널 레벨 스레드 4개, 사용자 레벨 스레드 3개,

2개의 순수 커널 레벨 스레드
TCB1, TCB2

  • 이들 스레드의 주소 공간은 커널에 있음.
  • 부팅 때부터 커널에서 실행되도록 만들어진 스레드

2개의 커널 레벨 스레드
프로세스당 하나의 커널 레벨 스레드(main) 자동 생성

  • TCB3
    커널은 단일 스레드 프로세스1을 적재할 때 자동으로 main 스레드 TCB3 생성
    커널이 프로세스1을 실행시키기 위함
  • TCB4
    커널은 멀티프로세스2를 적재할 때 자동으로 main 스레드 TCB4 생성
    커널이 프로세스2를 실행시키기 위함
    TCB3, TCB4의 스레드 주소 공간은 사용자 공간에 있음

3개의 사용자 레벨 스레드

  • 프로세스2의 main() 함수가 라이브러리 함수를 호출하여
    자신을 사용자 레벨 스레드로 등록
    U-TCB1 생성
  • 프로세스2의 main() 함수가 라이브러리 함수를 호출하여
    2개의 사용자 레벨 스레드 추가 생성
    U-TCB2, U-TCB3 생성

스레드 스케줄링
커널에 의한 스케줄

  • 코어1: TCB2 실행(TCB2가 가리키는 커널 스레드 코드2 실행)
  • 코어2: TCB4 실행(TCB4가 가리키는 프로세스 내의 코드 실행)
    처음에는 프로세스2의 main() 함수에서 실행을 시작하지만,
    현재 어떤 함수의 코드를 실행하고 있는지 알 수 없음

    커널은 프로세스2 내에 하나의 스레드만 있다고 생각함

프로세스2에서의 사용자 스레드 스케줄링
스레드 라이브러리가 3개의 사용자 레벨 스레드 스케줄

4.3 사용자 레벨 스레드의 유용성

초기에는 커널 레벨 스레드만 존재
→ 컨텍스트 스위칭에 많은 시간 소요
→ 커널의 도움 없이 스레드를 만들 수 있는 스레드 라이브러리 등장

스레드를 지원하지 않는 운영체제에서도 스레드 라이브러리를 이용하여 멀티스레드 응용프로그램을 작성할 수 있는 장점이 있음

4.4 사용자 레벨 스레드와 커널 레벨 스레드의 비교

4.5 커널 레벨 스레드와 사용자 레벨 스레드의 장단점


컨텍스트 스위칭과 스레드 관리

사용자 레벨 스레드 > 커널 레벨 스레드

커널 레벨 스레드

  • CPU의 레지스터들을 커널 내 TCB에 저장 및 TCB 리스트 조작
  • CPU 캐시에 코드와 데이터 교체
  • TLB(Translation Look-aside Buffer)의 내용이 교체되는 오버헤드 발생

사용자 레벨 스레드

  • 사용자 공간에서 진행되므로 커널 모드로의 변환 과정이 없음
  • CPU에 컨텍스트를 쓰거나 읽어오는 작업이 없음

이식성 및 활용성

사용자 레벨 스레드 > 커널 레벨 스레드

사용자 레벨 스레드

  • 스레드 라이브러리에 의해 관리되므로, 운영체제에 종속적이지 않음
  • 멀티스레드를 지원하지 않는 운영체제에서도
    멀티스레드 응용프로그램 작성 가능

실행 블록킹

사용자 레벨 스레드 < 커널 레벨 스레드

커널 레벨 스레드

  • 임의의 커널 레벨 스레드가 중단(블록)된다고 하더라도,
    응용프로그램 내 다른 커널 레벨 스레드가 스케줄링되어 실행될 수 있기 때문에 응용프로그램 전체가 중단되는 일은 발생하지 않는다.

사용자 레벨 스레드

  • 임의의 사용자 레벨 스레드가
    read()write() 시스템 호출을 실행하여 블록 상태가 될 때, 응용프로그램 내 모든 사용자 레벨 스레드가 실행될 수 없게 됨

병렬성

사용자 레벨 스레드 < 커널 레벨 스레드

커널 레벨 스레드

  • 4개의 코어가 존재한다면 4개의 커널 레벨 스레드를 동시에 실행시킬 수 있음

사용자 레벨 스레드

  • 4개의 코어가 존재한다고 하더라도,
    스레드 라이브러리에 의해 번갈아가면서 실행됨
    멀티 코어에 대한 활용성이 떨어짐

05. 멀티스레드 구현

5.1 배경


멀티스레드의 구현이란?

응용프로그램에서 작성한 스레드가 시스템에서 실행되도록 구현하는 방법

  • 사용자가 만든 스레드가 시스템에서 스케줄되고 실행되도록 구현하는 방법
  • 스레드 라이브러리와 커널의 시스템 호출의 상호 협력 필요
    리눅스의 경우 pthread 라이브러리의 pthread_create() 함수를 호출하여 스레드를 생성하는데, 생성되는 스레드가 사용자 레벨 스레드인지, 커널 레벨 스레드인지 생각하지 않고 프로그램을 작성함.

응용프로그램에서 생성된 사용자 레벨 스레드의 코드가
CPU에 의해 실행되려면 커널에 의해 스케줄되어야 함

→ 사용자 레벨 스레드와 커널 레벨 스레드가 연계(매핑, mapping)되어야 함

  • N:1 매핑
  • 1:1 매핑
  • N:M 매핑

5.2 N:1 매핑

  • 모든 프로세스를 단일 스레드 프로세스(single-thread process)로 다룸
  • 커널은 프로세스 당 1개의 커널 레벨 스레드(TCB) 생성
    프로세스의 모든 사용자 레벨 스레드가 1개의 커널 레벨 스레드에 매핑
  • 사용자 레벨 스레드는 스레드 라이브러리에 의해 스케줄되고 스위칭됨

장점

  • 단일 코어 CPU에서
    멀티스레드 응용프로그램의 실행 속도가 전반적으로 빠르다
    스레드 생성, 스케줄, 동기화 등에 있어서
    커널 진입 없이 사용자 공간에서 이루어지기 때문

단점

  • 멀티 코어 CPU가 보편화된 현대 컴퓨터에서 비효율적
    프로세스에 속한 여러 사용자 레벨 스레드들의 병렬 처리 안됨

  • 하나의 사용자 레벨 스레드가 블록되면 프로세스 전체 블록(병렬성이 없음)
    프로세스 내 다른 사용자 레벨 스레드로 스위칭되지 못함

5.3 1:1 매핑

  • 사용자 레벨 스레드 당 1개의 커널 레벨 스레드(TCB) 생성
  • 사용자 레벨 스레드는 매핑된 커널 레벨 스레드가 스케줄되면 실행

    스레드 라이브러리가 1:1 매핑을 하도록 만들어져 있음
    오늘날 대부분의 운영체제에서 1:1 매핑을 사용함

장점

  • 개념이 단순하여 구현이 용이
  • 멀티 코어 CPU에서 멀티프로세스 응용프로그램에게 높은 병렬성 제공
  • 하나의 사용자 레벨 스레드가 블록되어도 응용프로그램 전체가 블록되지 않음

단점

  • 커널에게 부담스러운 정책
  • 사용자 레벨 스레드가 많아지면 모두 커널의 부담

5.4 N:M 매핑

  • N개의 사용자 레벨 스레드를 M개의 커널 레벨 스레드에 매핑

    3:2 매핑 사례

장점

  • 1:1 매핑에 비해 커널 엔터티 수가 적어 커널의 부담이 적음

단점

  • 구현하기 복잡하여 현대의 운영체제에서는 거의 사용되지 않음

0개의 댓글