580 likes | 603 Views
POSIX thread. SSLab. 신장열. CONTENTS. Thread 의 생성 및 종료 Join and detach Cleanup handler Mutex Condition variable Thread signal Thread cancel. pthread_create (). Arguments pthread_t *th 생성된 thread 에 대한 식별자 (identifier) 에 대한 구조체 pointer pthread_attr_t *attr
E N D
POSIX thread SSLab. 신장열
CONTENTS • Thread의 생성 및 종료 • Join and detach • Cleanup handler • Mutex • Condition variable • Thread signal • Thread cancel
pthread_create () • Arguments • pthread_t *th • 생성된 thread에 대한 식별자(identifier)에 대한 구조체 pointer • pthread_attr_t *attr • thread 의 특성을 지정하기 위해 사용, default thread를 사용하면 NULL • void *(start_routine)(void *) • 분기 시켜서 실행할 thread 함수 • void *arg • start_routine 함수에 넘겨줄 argument • Return value • 성공하면 0을 return, 에러가 발생하면 non-zero를 return하고 errno를 설정 • errno • EAGAIN – 새 thread에 할당할 자원(thread 개수제한 포함)이 없거나 이미 생성된 thread #include <pthread.h> int pthread_create ( pthread_t *th, const pthread_attr *attr, void *(*start_routine)(void *), void *arg )
pthread_exit () • 현재 실행중인 thread를 종료 • cleanup handler • pthread_cleanup_push로 cleanup handler가 정의되어 있다면 pthread_exit가 내부적으로 호출 • Arguments • void *retval • Thread가 종료할 때의 return value #include <pthread.h> void pthread_exit(void *retval);
Example 1 #include <stdio.h> #include <string.h> #include <pthread.h> pthread_t threads[5]; int done[5]; void *thread_main(void *); int main(void) { int i; int rc; int status; printf("pid=%d\n", getpid()); for (i = 0; i < 5; i++) { done[i] = 0; pthread_create(&threads[i], NULL, &thread_main, (void *)i); printf("%d, %d\n", i, threads[i]); }
Example 1 for (i = 4; i >= 0; i--) { done[i] = 1; rc = pthread_join(threads[i], (void **)&status); if (rc == 0) { printf("Completed join with thread %d status= %d\n",i, status); } else { printf("ERROR; return code from pthread_join() is %d, thread %d\n", rc, i); return -1; } } return 0; }
Example 1 void *thread_main(void *arg) { int i; double result=0.0; printf("thread: %d, %d\n", (int)arg, getpid()); while (!done[(int)arg]) { for (i=0; i < 1000000; i++) { result = result + (double)random(); } printf("thread: %d, result = %e\n", (int)arg, result); } pthread_exit((void *) 0); }
Join and Detach • Join • pthread_join을 호출한 thread는 thread에 대한 종료를 기다림 • Thread는 자신의 종료상태를 main thread에 통보 • Detach • Thread가 프로세스와 분리 • 자신이 사용했던 자원을 바로 반납 • Thread가 어떻게 종료되던지 상관이 없게 되었을 때 detach시킨다.
pthread_join () • waitpid ()와 유사, thread가 종료하기를 기다린다. • Arguments • pthread_t thread • join할 thread identifier • void **thread_return • thread의 return value • Return value • 성공하면 0, 에러가 발생하면 non-zero를 return하고 errno를 설정 • errno • ESRCH – th에 해당하는 thread를 찾을 수 없다 • EINVAL – thread가 detatch되었거나 다른 thread가 이미 waiting 중 • EDEADLK – th가 자기 자신일 때 #include <pthread.h> int pthread_join(pthread_t th, void **thread_return);
pthread_detach () • thread를 분리시킨다. 분리된 thread는 pthread_join ()으로 기다릴 수 없다. • Arguments • pthread_t th • detach된 thread는 pthread_join을 호출하지 않아도 자동으로 모든 resource가 free된다. • Return value • 성공하면 0, 에러가 발생하면 non-zero를 return하고 errno를 설정 • errno • ESRCH – th에 해당하는 thread를 찾을 수 없다 • EINVAL – thread 가 이미 detach되어 있다. #include <pthread.h> int pthread_detach(pthread_t th);
pthread_self () • Return value • 자기 자신의 thread identifier를 return #include <pthread.h> pthread_t pthread_self ( void );
Example 2 #include <stdio.h> #include <string.h> #include <pthread.h> pthread_t threads[5]; int done[5]; void *thread_main(void *); int main(void) { int i; int rc; int status; printf("pid=%d\n", getpid()); for (i = 0; i < 5; i++) { done[i] = 0; pthread_create(&threads[i], NULL, &thread_main, (void *)i); printf("%d, %d\n", i, threads[i]); }
Example 2 for (i = 4; i >= 0; i--) { done[i] = 1; rc = pthread_join(threads[i], (void **)&status); /* detach thread에서는 사용할 필요 없다. */ if (rc == 0) { printf("Completed join with thread %d status= %d\n",i, status); } else { printf("ERROR; return code from pthread_join() is %d, thread %d\n", rc, i); return -1; } } // sleep(5); return 0; }
Example 2 void *thread_main(void *arg) { int i; double result=0.0; pthread_detach(pthread_self()); /* 쓰레드 분리 */ printf("thread: %d, %d\n", (int)arg, getpid()); while (!done[(int)arg]) { for (i=0; i < 1000000; i++) { result = result + (double)random(); } printf("thread: %d, result = %e\n", (int)arg, result); } pthread_exit((void *) 0); }
Cleanup handler • thread를 일종의 객체로 생각하면 객체의 destructor(소멸자)와 동일 • 객체가 할당 받은 자원을 시스템에 돌려준다 • Lock중인 mutex를 unlock • malloc()등으로 할당받은 memory를 free • File descriptor나 socket등도 close
pthread_cleanup_push () • Cleanup handler를 등록 • Arguments • void (*routine) (void *) • cleanup handler • void *arg • Cleanup handler function의 arguments • cleanup handler • 할당받은 resource를 되돌려주거나 mutex lock등을 해제 #include <pthread.h> void pthread_cleanup_push ( void (*routine) (void *), void *arg );
pthread_cleanup_pop () • 등록된 cleanup handler를 제거 • Arguments • int excute • 0이 아니면 cleanup handler를 실행 • 0이면 실행시키지 않고 제거 #include <pthread.h> void pthread_cleanup_pop ( int execute );
Mutex • Pthread 자체에서 제공하는 동기화 기법 • MUTual EXclusion 의 약자 • Lock or unlock (Binary Semaphore) • Mutex를 사용할 때 주의할 점 • Deadlock • mutex의 파괴 • 다른 thread가 lock한 mutex를 unlock • 간단한 뮤텍스 생성 방법 • pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_init () • Mutex를 초기화 • Arguments • pthread_mutex_t *mutex • 초기화할 mutex 객체 • pthread_mutex_attr *attr • Mutex에 지정할 attribute. Default는 NULL • Return Value • 항상 0을 return #include <pthread.h> int pthread_mutex_init (pthread_mutex_t *mutex, pthread_mutex_attr *attr );
pthread_mutex_destroy () • Arguments • pthread_mutex_t *mutex • identifier에 해당하는 mutex를 제거한다. • Lock되어있는 mutex는 제거할 수 없다. • Return Value • 성공하면 0, 실패하면 non-zero을 return하고 errno를 설정 • errno • EBUSY – mutex가 현재 lock되어있다. #include <pthread.h> int pthread_mutex_destroy ( pthread_mutex_t *mutex );
pthread_mutex_lock () • mutex를 lock중이면 mutex가 unlock될 때까지 block된다. • Arguments • pthread_mutex_t *mutex • mutex identifier에 해당하는 mutex를 lock한다. • Return Value • 성공하면 0, 실패하면 non-zero을 return하고 errno를 설정 • errno • EINVAL – mutex가 제대로 초기화 되어 있지 않다. • EDEADLK - 이미 잠금을 얻은 쓰레드가 다시 잠금을 요청할 때 #include <pthread.h> int pthread_mutex_lock ( pthread_mutex_t *mutex );
pthread_mutex_trylock () • pthread_mutex_lock의 nonblocking 버젼 • Arguments • pthread_mutex_t *mutex • mutex identifier에 해당하는 mutex에 lock을 시도한다. • Return Value • 성공하면 0, 실패하면 non-zero을 return하고 errno를 설정 • errno • EBUSY - mutex가 잠겨 있어서 잠금을 얻을 수 없다. • EINVAL - mutex가 잘못 초기화 되었다. #include <pthread.h> int pthread_mutex_trylock ( pthread_mutex_t *mutex );
pthread_mutex_unlock () • Arguments • pthread_mutex_t *mutex • mutex identifier에 해당하는 mutex를 unlock한다. • Return Value • 성공하면 0 을 return, 실패하면 non-zero을 return하고 errno를 설정 • errno • EINVAL – mutex가 제대로 초기화 되어있지 않다. • EPERM – mutex가 이 함수를 호출한 thread에게 lock되지 않았다. #include <pthread.h> int pthread_mutex_unlock ( pthread_mutex_t *mutex );
Condition Variable • Thread 간의 signaling 기법 • 특정 event나 조건이 충족되었음을 하나 혹은 모든 thread에게 알림 • Mutex 잠금과 함께 사용되어 mutex를 자동으로 얻을 수 있다.
pthread_cond_init () • Arguments • pthread_cond_t *cond • 초기화할 condition variable • const pthread_cond_attr *attr • condition variable의 attribute • Return value • 성공하면 0을 return • errno • EAGAIN – 새로운 condition variable을 할당할만한 resource가 부족 • ENOMEM – condition variable 을 초기화할 만한 memory가 부족 • EBUSY – 이미 초기화된 condition variable을 재초기화 • EINVAL – attr 변수의 attribute 지정이 잘못 #include <pthread.h> int pthread_cond_init( pthread_cond_t *cond, const pthread_cond_attr *attr );
pthread_cond_destroy () • Arguments • pthread_cond_t *cond • 제거할 condition variable • Return value • 성공하면 0을 return • errno • EBUSY – pthread_cond_wait()나 pthread_cond_timedwait())을 이용해 다른 thread가 condition variable을 기다리고 있음 • EINVAL – cond의 값이 잘못되었다. #include <pthread.h> int pthread_cond_destroy ( pthread_cond_t *cond );
pthread_cond_signal () • Condition variable에 signal을 보내 pthread_cond_timewait()이나 pthread_cond_wait()으로 기다리고 있던 thread를 하나 깨운다. (어느 것이 깨어날지는 알 수 없다.) • Arguments • pthread_cond_t *cond • Signal을 보낼 condition variable • Return value • 성공하면 0 을 return • errno • EINVAL – cond 값이 초기화 되지 않았다. #include <pthread.h> int pthread_cond_signal ( pthread_cond_t *cond );
pthread_cond_broadcast () • Condition variable에 signal을 보내 pthread_cond_timewait()이나 pthread_cond_wait()으로 기다리고 있던 thread를 모두 깨운다. • Arguments • pthread_cond_t *cond • Signal을 보낼 condition variable • Return value • 성공하면 0을 return • errno • EINVAL – cond 값이 초기화 되지 않았다. #include <pthread.h> int pthread_cond_broadcast ( pthread_cond_t *cond );
pthread_cond_wait () • 조건변수 cond로 시그널이 전달되기를 기다린다. • 시그널을 전달받아 쓰레드가 깨어나면 자동적으로 mutex lock을 획득 • Arguments • pthread_cond_t *cond • 기다릴 condition variables • pthread_mutex_t *mutex • Condition variable에 의해 lock을 얻을 mutex • Return value • 성공하면 0을 return • errno • EINVAL – 인자의 값이 잘못 초기화 되어있거나 같은 condition variable에 다른 mutex가 연결되었다. (pthread_cond_wait ()와 pthread_cond_timewait ()의 동시 사용의 경우) • EPERM – 현재 thread에 mutex가 주어지지 않았다. #include <pthread.h> int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex);
pthread_cond_timewait • 지정된 시간까지 condition variable에 signal이 오기를 기다린다. • 그외에는 pthread_cond_wait와 거의 동일 • Return value • 성공하면 0을 return • errno • ETIMEDOUT – 지정된 시간이 지났다. • 참고 • abstime에 대해서는 time()와, gettimeofday()를 참고 #include <pthread.h> int pthread_cond_timewait ( pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime );
Example 3 #include <pthread.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <vector> #include <iostream> using namespace std; void *ping(void *); void *pong(void *); pthread_mutex_t sync_mutex; pthread_cond_t sync_cond; pthread_mutex_t gmutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t gcond = PTHREAD_COND_INITIALIZER;
Example 3 int main() { vector<void *(*)(void *)> thread_list; vector<pthread_t> tident(10); int thresult; int status; int i; pthread_mutex_init(&sync_mutex, NULL); pthread_cond_init(&sync_cond, NULL); thread_list.push_back(pong); thread_list.push_back(ping); for(i = 0; i < thread_list.size(); i++ ) { pthread_mutex_lock(&sync_mutex); if (pthread_create(&tident[i], NULL, thread_list[i], (void *)NULL) <0) { perror("error:"); exit(0); } pthread_cond_wait(&sync_cond, &sync_mutex); pthread_mutex_unlock(&sync_mutex); } for (i = 0; i < tident.size(); i++) { pthread_join(tident[i], (void **)&status); } }
Example 3 void *ping(void *data) { int i=0; pthread_mutex_lock(&sync_mutex); pthread_cond_signal(&sync_cond); pthread_mutex_unlock(&sync_mutex); while(1) { pthread_mutex_lock(&gmutex); printf("%d : ping\n", i); pthread_cond_signal(&gcond); pthread_cond_wait(&gcond, &gmutex); pthread_mutex_unlock(&gmutex); usleep(random()%100); i++; } }
Example 3 void *pong(void *data) { int i = 0; pthread_mutex_lock(&sync_mutex); sleep(1); pthread_cond_signal(&sync_cond); pthread_mutex_unlock(&sync_mutex); while(1) { pthread_mutex_lock(&gmutex); pthread_cond_wait(&gcond, &gmutex); printf("%d : pong\n", i); pthread_cond_signal(&gcond); pthread_mutex_unlock(&gmutex); i++; } }
pthread_attr_init ()pthread_attr_destroy () • Thread에 대한 속성을 초기화하거나 제거한다. • Arguments • pthread_attr_t *attr • Thread에 대한 속성 변수 • Return value • 성공하면 0을 return • errno • ENOMEM – thread attribute에 할당할 memory가 부족 #include <pthread.h> int pthread_attr_init ( pthread_attr_t *attr ); int pthread_attr_destroy ( pthread_attr_t *attr );
pthread_attr_getscope () pthread_attr_setscope () • Thread에 대한 scope 속성을 알아내거나 혹은 세팅한다. • Arguments • int *scope • attr에서 Scope를 받아올 변수 • int *contentionscope • attr에 세팅할 scope • Return value • 성공하면 0을 return • errno • EINVAL – contentionscope의 값이 잘못되었다. • ENOTSUP – 지원되지 않은 value로 set하려고 했다. #include <pthread.h> int pthread_attr_getscope (const pthread_attr_t *attr, int *scope); int pthread_attr_setscope (pthread_attr_t *attr, int contentionscope);
pthread_attr_getdetachstate ()pthread_attr_setdetachstate () • Arguments • const pthread_attr_t *attr, pthread_attr_t *attr • thread의 attr를 가지고 있는 변수 • int *detachstate , int detachstate • 값을 얻어 오거나 설정 • Return value • 성공하면 0을 return • errno • EINVAL – detachstate의 값이 잘못되었다. #include <pthread.h> int pthread_attr_getdetachstate ( const pthread_attr_t *attr, int *detachstate ); int pthread_attr_setdetachstate ( pthread_attr_t *attr, int detachstate );
pthread_sigmask () • 특정 thread만 특정 signal을 받도록 할 수 있다. • Arguments • int how • SIG_BLOCK – 지금 현재의 값에 newmask된 값 부분만 block • SIG_UNBLOCK – 지금 현재의 값에 newmask된 값 부분만 unblock • SIG_SETMASK – 현재 thread의 mask를 newmask로 교체 • sigset_t *newmask • sigset_t *oldmask • Return value • 성공하면 0 • errno • EINVAL – how의 값이 잘못되었다. • 참조 • sigsetmask (), sigemptyset (), sigfillset (), sigaddset (), sigaction () #include <pthread.h> #include <signal.h> int pthread_sigmask(int how, const sigset_t *newmask, sigset_t *oldmask);
pthread_kill () • 프로세스 내의 thread에 signal을 보낸다 • Arguments • pthread_t thread • Signal을 보낼 thread • int signo • Thread에 보낼 signal 번호 • Return value • 성공하면 0을 return • errno • ESRCH – 주어진 thread identifier에 맞는 thread를 찾을 수 없다 • EINVAL – signo의 값이 지원되지 않는 signal number이다. • 참조 • kill (), sigwait (), sigtimewait(), #include <pthread.h> #include <signal.h> int pthread_kill(pthread_t thread, int signo);
Example 4 #include <pthread.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <stdio.h> pthread_t thread_t[3]; void sig_handler(int signo) { printf("Thread Stop %d:\n", (int)pthread_self()); sleep(100); } void null(int signo) { printf("Thread Start\n"); }
Example 4 void *test(void *data) { sigset_t newmask; struct sigaction act, act2; int i = 0; sigemptyset(&newmask); sigaddset(&newmask, SIGUSR1); sigaddset(&newmask, SIGCONT); act.sa_handler = sig_handler; act2.sa_handler = null; sigaction(SIGUSR1, &act, NULL); sigaction(SIGCONT, &act2, NULL); pthread_sigmask(SIG_UNBLOCK, &newmask, NULL); while(1) { printf("Im child Thread %d %d\n", (int)pthread_self(),i); i++; sleep(1); } }
Example 4 void *worker(void *data) { sigset_t newmask; sigemptyset(&newmask); sigaddset(&newmask, SIGUSR1); sigaddset(&newmask, SIGCONT); pthread_sigmask(SIG_BLOCK, &newmask, NULL); while(1) { sleep(2); pthread_kill(thread_t[0], SIGUSR1); sleep(3); pthread_kill(thread_t[0], SIGCONT); } } int main() { pthread_create(&thread_t[0], NULL, test, NULL); pthread_create(&thread_t[1], NULL, test, NULL); pthread_create(&thread_t[2], NULL, worker, NULL); pthread_join(thread_t[0], NULL); pthread_join(thread_t[1], NULL); return 1; }
pthread_cancel () • Arguments • pthread_t thread • 강제로 종료시킬 thread의 identifier • 종료 요청을 받은 thread는 thread_exit(PTHREAD_CANCELD)를 수행 (cleanup handler도 당연히 수행됨) • 해당 thread의 return value는 PTHREAD_CANCELD • Return value • 성공하면 0 • errno • ESRCH • 쓰레드 식별자 thread를 가지는 쓰레드가 존재하지 않는다. #include <pthread.h> int pthread_cancel (pthread_t thread );
pthread_setcancelstate () • Arguments • int state • PTHREAD_CANCEL_ENABLE – 이 thread를 cancel할 수 있음 • PTHREAD_CANCLE_DISABLE – 이 thread를 cancel할 수 없음 • int *oldstate • 바로 이전의 cancel state • Return value • 성공하면 0을 return • errno • state의 값이 PTHREAD_CANCEL_ENABLE 이나 PTHREAD_CANCEL_DISABLE가 아닐 때 #include <pthread.h> int pthread_setcancelstate(int state, int *oldstate);
pthread_setcanceltype () • Arguments • int type • PTHREAD_CANCEL_DEFERRED – 바로 cancel됨 • PTHREAD_CANCLE_ASYNCHRONOUS – 취소지점까지 기다린다. • int *oldtype • 바로 이전의 cancel type • Return value • 성공하면 0을 return • errno • type의 값이 PTHREAD_CANCEL_DEFERRED 이나 PTHREAD_CANCEL_ASYNCHRONOUS가 아닐 때 #include <pthread.h> int pthread_setcanceltype(int type, int *oldtype);