Thread Background
- Concurrent processing은 process가 너무 무겁다.
- process에는 address space(code), OS resource(open file)..., contest(실행 상태 정보, reg).. 등이 존재한다.
- 즉, fork()를 한다면 시간과 memory가 매우 costly하다.
- 이러한 단점들이 존재했기 때문에 공유할 수 있는 것은 공유하고 실행 할 때 다른 것만 분리를 하는 것이 필요해졌다.
Thread

- process 내부에서 독립적인 제어 흐름을 가지는 단위
- 1개의 process는 1개의 thread를 가진다.
- multi thread process는 1개의 process 내에 여러개의 thread를 가진다. → multi thread는 process를 공유한다.
- thread는 CPU의 scheduling 단위이다.
- thread 구성 : thread ID, program counter, register를 부여 / stack은 별도로 지원한다.

- 대부분 현대 OS는 multi thread를 지원한다.
- multi thread 사용 예시 : web browser / word processor / ...
- 대부분 OS는 MT-safe lib func을 지원한다.
- Multi Thread - safe library function : multi thread를 목적으로 생각한 function들을 모아둔 library
- ex) POSIX pthread standard API : OS 개발자가 implement한다.
pthreads

- <pthread.h> 헤더파일의 pthread library
- libpthread.a library를 link해야한다.
- compile option : -lpthread
$ gcc test.c -lpthread
pthread_create
#include <pthread.h>
int pthread_create(pthread_t *thread,
pthread_attr_t* attr,
void *(*start_routine)(void *),
void *arg);
- thread를 생성하는 API
- *thread : thread id
- *attr : 환경 설정(default : NULL)
- *start_routine : 실행 작업(=function)
- *arg : start_routine에 사용되는 인자
- return : 성공 시 0 / 실패 시 error number
- 모든 thread는 생성되면 독립적으로 동작한다.
- 기본적으로 process는 main thread를 가진다.
- 1개의 process 내에 thread의 생성에는 maximum이 정해져 있다. (default : 388547)
Terminating pthread
- pthread가 종료되는 여러가지 방법이 존재한다.
1) 전달 함수가 종료되면 thread가 종료
2) pthread exit을 불러서 thread 종료
3) pthread_id를 이용해서 pthread_cancel을 호출하여 종료
4) process 자체가 종료되면 관련 thread들이 전부 종료
void pthread_exit(void *retval)
- 특정 thread에서 자신 thread를 종료한다.
- void type은 모든 자료형을 포괄하기 위해 사용된다.
- pthread_exit을 할 때 open file을 닫지 않고, process가 종료될 때 닫는다.
if main()함수가
1) pthread_exit() : 다른 thread는 실행하고 main만 종료됨
2) exit() : 다른 모든 thread가 종료(process가 종료)
Thread Attribute
- thread가 생성될 때, thread의 속성은 joinable / detached로 정의된다.
1. joinable thread
- thread가 종료되면 기존 thread와 합쳐진다 → resource 회수
- 생성 시 default thread attribute이다.
2. detached thread
int pthread_detach(pthread_tid);
- 독립적으로 관리되며 thread 종료 시 즉시 resource를 반환한다.
- pthread_detach 함수로 분리해야 한다.
- 한번 type을 detached로 바꾸면 다시 joinable로 돌아가지 못한다.
pthread_join

int pthread_join(pthread_t tid, void **retval);
- id의 thread가 종료될 때 까지 기다리는 함수
- arg를 넘겨줄 때까지 block된다.
- 만약 취소가 된다면 PTHREAD_CANCELED가 retval에 저장된다.
**retval에서 **인 이유?
- exit에서 보내는 type = *retval 이 주소 or integer일 지 모르기 때문에, 그 값을 담을 수 있는 pointer 변수이다.
Getting Thread ID
pthread_self
int pthread_self(void);
pthread_equal
int pthread_equal(pthread_t t1, pthread_t t2);
- return : 두 thread의 id가 동일하면 nonzero / 다르면 0
Thread를 비교할 때 " == " 사용하지 말기
- t1, t2는 id가 아닌 key고, key의 struct 내부에 있는 id를 가져와서 비교하는 것이기 때문
Thread Cancellation
pthread_cancel(pthread_t tid)
- thread가 완료되기 전에 종료하고싶을 때 사용
Cancellation type
asynchronous calnel
- 호출 시 즉시 thread를 종료
- 만약 thread가 현재 cancel 요청이 왔을 때 resource는 바로 반환한다.
- 중요한 작업 / 계산 중 / 공유 중일 때는 불시에 out될 수 있는 문제가 있다.
deferred cancel
- 지정 지점(cancellation point)까지 다 수행하고 cancel
- pthread_testcancel() 이 호출지점 → 이 후 cleanup
int pthread_setcancelstate(int state, int *oldstate);
int pthread_setcanceltype(int type, int *oldtype);

- state(mode) 내부 인자 → PTHREAD_CANCEL_?? 형식으로 입력
Implicit sharing
- 암묵적 공유 → user가 모르게 data가 공유되어 사용되는 상황
- 주소 값을 create할 때 사용하는 일에 발생한다.
- 현재 thread와 new thread 사이의 i 값을 공유
Mutex
Thread Synchronization
- 공통된 자원에 thread가 함께 접근했을 때 발생되는 문제
- race condition과 유사한 상황
Mutex
- 여러 thread 사이의 shared data를 보호하기 위해 lock을 하며 사용한다.
- 한 순간에 1개의 thread를 lock(acquire) 한다.
- 만일 여러 thread가 lock을 시도할 경우 OS가 1개의 thread만 lock 시킨다.
- 이 외의 thread들은 unlock이 될 때까지 대기한다.
Critical section
- shared data를 다루는 code 영역
- 오직 한 순간에 1개의 thread만 접근(작업)하도록 해야한다.
- mutually exclusive(상호 배제)를 해야한다.
pthread mutex creation
/* mutex object creation & destruction */
int pthread_mutex_init(*mutex, *attr);
int pthread_mutex_destroy(*mutex);
/* mutex attribute creation & destruction */
int pthread_mutexattr_init(*attr);
int pthread_mutexattr_destroy(*attr);
pthread_mutex_t *mutex
pthread_mutexattr_t *attr
- Mutex는 초기에 unlocked 상태이다.
- Mutex 변수는 선언 이후 초기화를 해줘야한다.
- Mutex 변수 초기화 방법
1) statically : pthread_mutex_t mymutex = THREAD_MUTEX_INITIALIZER
2) dynamic : pthread_mutex_init(attr)
pthread_mutexattr의 정의
- protocol : priority inversion을 막는 것
- prioceiling : priority ceiling(최고값) 설정
- process-shared : process 사이 mutex
→ 일반적으로는 그냥 default(NULL) 사용
Mutex Lock/Unlock
int pthread_mutex_lock(*mutex);
int pthread_mutexattr_unlock(*mutex);
pthread_mutex_t *mutex
pthread_mutexattr_t *attr
- return : 성공 시 0 / 실패 시 error number
- lock() : thread가 lock 상태라면 다른 thread는 block되어서 대기한다.
- unlock() : block 상태를 해제한다.
- unlock이 error나는 경우는 이미 unlock인 경우이거나 또 다른 thread가 mutex를 잡고 있는 경우이다.
int pthread_mutex_trylock(*mutex);
- non-blocking lock으로 lock이 가능한 상태가 아니면 바로 block을 한다.
Advisory locking
- programmer가 직접 lock을 적용하는 것(OS는 모름)
- 1개라도 lock-unlock을 하지 않으면 race condition이 발생할 수 있다.
- lock은 하고, unlock을 하지 않으면 프로그램이 정지된다.
Condition variables
- mutex를 사용하고 있는 thread 사이에서 synchronization을 위해 사용된다.
- thread는 mutex lock에서 condition을 기다리는 상황 → 자신이 기다리는 동안 mutex를 잠시 반납하는 것
- condition이 만족되면 원래 thread에게 signal을 전달하고 wake-up한다.
- condition variable은 mutex와 한 쌍으로 다닌다.
- condition을 대기 Queue로 해석하면 된다.
Create/destroy condition variable
/* condition variable creation & destruction */
int pthread_cond_init(*condition, *attr);
int pthread_cond_destroy(*condition);
/* condition attribute creation & destruction */
int pthread_condattr_init(*attr);
int pthread_condattr_destroy(*attr);
pthread_cond_t* condition
pthread_condattr_t *attr
- condition variable 초기화 방법
1) static : pthread_cond_t myconvar = PTHREAD_COND_INITIALIZER;
2) dynamic : pthread_cond_init(*condition, *attr);
Waiting/Signalling Condition Variables
pthread_cond_wait(condition, mutex);
pthread_cond_signal(condition);
pthread_cond_broadcast(condition);
pthread_cond_t *condition
pthread_condattr_t *attr
- return : 성공 시 0 / 실패 시 error value
- wait() : condition이 만족될 때까지 block = 깨워줄 때까지(=signal/broad)
- condition을 기다릴 때는 mutex를 잠시 반납하고, 다른 thread가 c-s에 들어온다.
- wake-up 하면 자신이 사용하던 mutex를 lock한다.
- signal() : condition의 맨 앞 thread를 호출한다.
- signal을 호출 했을 때, wait하던 thread가 없다면 그냥 호출 종료된다.
- broadcast() : condition의 thread를 전부 호출한다.