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임.
반응형
'CS 지식 > 시스템 프로그래밍' 카테고리의 다른 글
[C언어] Deadlock(교착상태) 원인과 해결법 (0) | 2025.01.28 |
---|---|
[C언어] pthread 라이브러리를 이용한 스레드 동기화 (0) | 2025.01.28 |
[C언어] 프로세스 간 통신 (IPC) (0) | 2024.10.18 |
Assembly(어쌤블리어)의 기초 (0) | 2024.10.18 |
[C언어] Signal 프로그래밍에서의 Race Condition과 해결법 (0) | 2024.10.17 |
댓글