Operating System: 17. 쓰레드 API
쓰레드 생성
#include "ptrhead.h"
int pthread_create(pthread_t *thread,
pthread_attr_t *attr,
void (*start_routine)(void *),
void *arg);
- thread는pthread_t 타입 구조체를 가리키는 포인터이다.
- 쓰레드와 상호작용하는 데 사용된다.
- attr은 쓰레드 속성을 지정하는 데 사용한다.
- 스택의 크기와 쓰레드들의 스케줄링 우선순위 같은 정보를 지정할 수 있다.
- start_routine은 실행할 함수를 나타내는 함수포인터이다.
- arg는 실행할 함수에 인자로 전달할 수 있다.
쓰레드 종료
int pthread_join(pthread_t thread, void **value_ptr);
- 다른 쓰레드가 작업을 완료할 때까지 기다린다.
- 두 개의 인자 중 첫 번째인 thread는 어떤 쓰레드를 기다리라고 하는지 명시하는 것이다.
- value_ptr은 반환값에 대한 포인터이다. 임의의 데이터를 반환할 수 있기에 void *타입으로 사용된다.
- 쓰레드의 콜 스택에 할당된 값을 가리키는 포인터를 반환하는 실수를 하지 않도록 한다.
- 특정 작업을 병렬적으로 실행하기 위해 쓰레드를 생성하는 병렬 프로그램의 경우 종료 혹은 다음 단계로 넘어가기 전에 병렬 수행 작업이 모두 완료되었다는 것을 확인하기 위해 join을 사용한다.
락
pthread_mutex_t lock;
pthread_mutex_lock(&lock);
x = x + 1; // 임계영역 코드
pthread_mutex_unlock(&lock);
- pthread_mutex_lock()가 호출되었을 때 다른 어떤 스레드도 락을 가지고 있지 않다면 이 쓰레드가 락을 얻어
임계 영역
에 진입할 수 있다.- 많은 쓰레드들이 락 획득 과정에서 대기중일 수 있으며, 락을 획득한 쓰레드만이 언락을 호출해야 한다.
- 락을 사용하기 전에 초기화하도록 한다. ```c pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
int rc = pthread_mutex_init(&lock, NULL); assert(rc == 0);
int rc = pthread_utex_lock(mutex) assert(rc == 0);
- 이 루틴의 첫번째 주소는 락 자체의 주소이고, 두 번째 인자는 선택가능한 속성이다.
- 실제 복잡한 프로그램에서, 락이나 언락이 실패한 경우 그냥 종료하면 안되고 적절한 대응을 하도록 한다.
## 컨디션 변수
- 한 쓰레드가 계속 진행하기 전에 다른 쓰레드가 무언가를 해야 하는 쓰레드 간에 일종의 시그널 교환 메커니즘이 필요할 때 컨디션 변수가 사용된다.
```c
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_mutex_signal(pthread_cond_t *cond);
- 컨디션 변수를 사용하기 위해서는 컨디션 변수와 연결된 락이
반드시
ㅈ 존재해야 한다. ```c pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHRAD_COND_INITIALIZER;
pthread_mutex_lock(&lock); while (ready == 0) Pthread_cond_wait(&cond, &lock); Pthread_mutex_unlock(&lock); ```
- pthread_cond_wait()는 호출 쓰레드를 수면(sleep)상태로 만들고 다른 쓰레드로부터 시그널을 대기한다. 현재 수면 중인 쓰레드가 관심 있는 무언가가 변경되면 시그널을 보낸다.
- 시그널을 보내고 전역 변수 ready를 수정할 때 반드시 락을 가져야 한다.
- 시그널 대기 함수는 락을 두번째 인자로 받고 있지만, 시그널 보내는 함수에서는 조건만을 인자로 받고 있다. 시그널 대기 함수는 호출 스레드를 재우는 것 외에도
락을 반납해야 하기 때문
이다. - pthread_cond_wait()는 깨어나서 리턴하기 직전에 락을 다시 획득한다.
- ready 변수를 체크할 때, while로 사용하는 것이 안전하다.