본문 바로가기
CS 지식/시스템 프로그래밍

[C언어] 스레드의 개념과 pthread 라이브러리

by 코딩하는 동현😎 2025. 1. 28.

Thread 개요

  • 실행의 최소 단위이고 함수를 실행한다.
  • 자체적인 논리적인 control flow를 가진다.
  • 각각 쓰레드는 자체의 스택과 지역변수를 가지지만 다른 쓰레드에게 보호받지 않는다.
  • 각각 쓰레드는 자체의 TID(thread ID)를 가진다.
  • 각각 쓰레드는 프로세스의 context에 실행되며 global data와 같은 코드를 공유한다.
  • 통상적으로 프로세스보다 더 오버헤드가 작다(경량화).

가상 주소 공간 비교

  • 왼쪽은 프로세스가 2개일 때이고, 오른쪽은 하나의 프로세스 영역에서 User stack에 Thread1, Thread2가 할당되는 것을 볼 수 있다.
  • 같은 프로세스의 data, code, heap 공유
  • 독자적인 stack, PC, 레지스터를 할당받음.

fork vs exec vs pthread_create

fork, exec는 프로그램 코드를 복사하기 때문에 오버헤드가 크지만, 스레드는 유지한채로 프로그램 카운터만 옮기므로 오버헤드가 작다.

fork

exec

  • 복사하고 지우고 다시 쓰기 때문에 오버헤드가 큼.

pthread_create

  • 프로그램 카운터만 움직임.


Creating Threads

int pthread_create(pthread_t *thread,
                   const pthread_attr_t *attr,
                   void *(*start)(void *), // 실행할 함수 이름
                   void *arg)              // 함수의 arg 구조체

-lthread, -pthread 등으로 link 할 수 있다.


Thread ID 구하는 법

  • pthread_create()의 반환값
  • pthread_self()
  • gettid()
  • thread ID는 한 프로세스 안에서만 고유하고, n개 프로세스에선 TID가 고유하다는 것을 보장받지 않는다.

pthread_attr_t (보통 NULL)

초기화

  • int pthread_attr_init(pthread_attr_t *tattr)
    • 구조체를 초기화. 스레드 속성을 설정하기 전에 호출되어야 함.

분리 상태 (Detach State)

  • PTHREAD_CREATE_JOINABLE
    • 기본적으로 스레드는 종료 후 종료 상태를 기다릴 수 있도록 "joinable" 상태임.
    • 종료 상태와 ID가 보존됨.
  • pthread_attr_setdetachstate()

범위 (Scope)

  • PTHREAD_SCOPE_SYSTEM
    • 스레드가 시스템의 모든 다른 프로세스와 경쟁하여 자원을 할당받도록 설정.
  • pthread_attr_setscope()
    • 기본적으로 PTHREAD_SCOPE_PROCESS는 같은 프로세스 내에서만 스케줄링됨.

스케줄러 상속 (Inherit Scheduler)

  • PTHREAD_INHERIT_SCHED
    • 새로 생성된 스레드는 부모 스레드의 스케줄링 속성을 상속함.
  • pthread_attr_setinheritsched()

스케줄링 정책 (Scheduling Policy)

  • SCHED_OTHER
    • 새 스레드는 시스템의 기본 스케줄링 정책을 따름.
  • pthread_attr_setschedpolicy()

스케줄링 우선순위 (Scheduling Priority)

  • 0
    • 우선순위가 0으로 설정되면 스케줄링에 우선순위가 사용되지 않음.
  • pthread_attr_setschedparam()

보호 크기 (Guard Size)

  • 페이지 크기 (4KB)
    • 스택 오버플로우를 방지하기 위해 스레드는 페이지 크기만큼의 보호 공간을 가질 수 있음.
  • pthread_attr_setguardsize()

스택 크기 (Stack Size)

  • 8MB
    • 기본적으로 새로 생성되는 스레드는 8MB 크기의 스택을 가짐.
  • pthread_attr_setstacksize()

Resource Usage Limits

  • User resource limit: ulimit command
  • System resource limits:
    • /proc/sys/kernel/threads-max
    • /proc/sys/fs/file-max

Terminating Threads

void pthread_exit(void *retval)

  • 현재 스레드를 종료시키는 함수. 자신이 값을 남기고 감.
  • retval 값은 종료 시 반환되며, 같은 프로세스 내의 다른 스레드가 pthread_join()을 호출하면 이 값을 받을 수 있음.

int pthread_cancel(pthread_t thread)

  • 특정 스레드에 대해 종료 요청을 보내는 함수.
  • 해당 스레드는 종료될 때까지 실행을 계속할 수 있으며, 이 함수는 스레드를 즉시 종료시키지 않음. 스레드가 취소될 수 있는 지점에 도달해야 종료됨.

Joining Threads

int pthread_join(pthread_t thread, void **value_ptr)

  • 지정한 스레드가 종료될 때까지 호출한 스레드를 블록(대기)시키는 함수.
  • thread: 종료될 스레드의 식별자
  • value_ptr: 종료된 스레드의 반환 값을 받을 포인터 (pthread_exit()에서 반환한 값이 이곳에 저장됨).
  • 반환 값: 성공 시 0, 실패 시 오류 코드 반환.

스레드의 상태

  • Joinable Threads (기본값)
    • joinable 상태의 스레드는 종료될 때까지 메모리 자원이 자동으로 해제되지 않음. pthread_join()을 호출해야 자원이 회수됨.
    • 여러 스레드의 실행 결과를 수집해야 하는 경우에 적합.
  • Detached Threads
    • detached 상태의 스레드는 종료 후 메모리 자원이 자동으로 해제되며, pthread_join()을 호출할 필요가 없음.
    • 로그 기록, 데이터 처리 등 독립적인 작업을 수행하는 스레드에 유용.

Detach Threads

int pthread_detach(pthread_t thread)

  • 특정 스레드를 "detached" 상태로 설정.
  • 스레드가 종료될 때 OS에게 메모리 자원이 자동으로 해제되며, pthread_join()을 호출할 수 없음.

Get TID

int pthread_self()

  • POSIX 스레드 라이브러리에서 사용하는 스레드 ID를 반환.

gettid()

  • 커널 스레드 ID를 반환하며, 이는 실제 커널에서 관리하는 스레드 ID임.
반응형

댓글