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 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 void pthread_exit(void *retval);
Example 1 #include 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 < ; i++) { result = result + (double)random(); } printf("thread: %d, result = %e\n", (int)arg, result); } pthread_exit((void *) 0); }
Example 1
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 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 int pthread_detach(pthread_t th);
pthread_self () Return value – 자기 자신의 thread identifier 를 return #include pthread_t pthread_self ( void );
Example 2 #include 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 < ; i++) { result = result + (double)random(); } printf("thread: %d, result = %e\n", (int)arg, result); } pthread_exit((void *) 0); }
Example 2
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 void pthread_cleanup_push ( void (*routine) (void *), void *arg );
pthread_cleanup_pop () 등록된 cleanup handler 를 제거 Arguments –int excute 0 이 아니면 cleanup handler 를 실행 0 이면 실행시키지 않고 제거 #include 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 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 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 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 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 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 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 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 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 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 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 int pthread_cond_timewait ( pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime );
Example 3 #include 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 thread_list; vector 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++; }
Example 3
pthread_attr_init () pthread_attr_destroy () Thread 에 대한 속성을 초기화하거나 제거한다. Arguments –pthread_attr_t *attr Thread 에 대한 속성 변수 Return value – 성공하면 0 을 return errno –ENOMEM – thread attribute 에 할당할 memory 가 부족 #include 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 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 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 #include 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 #include int pthread_kill(pthread_t thread, int signo);
Example 4 #include 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; }
Example 4
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 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 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 int pthread_setcanceltype(int type, int *oldtype);
pthread_testcancel () 새로운 취소지점을 지정한다 –Cancel 요청이 들어와 있는지 검사한다. 그 외에 다음의 함수들이 취소지점이 된다. –pthread_join () –pthread_cond_wait () –pthread_cond_timewait () –sem_wait () –sigwait () #include void pthread_testcancel(void);
Example 5 #include void clean_up(void *); // 쓰레드 종료시 호출될 함수 void *thread_func(void *); // 쓰레드 함수 pthread_cond_t cond = PTHREAD_COND_INITIALIZER; pthread_mutex_t lmu = PTHREAD_MUTEX_INITIALIZER; int main(int argc, char **argv) { int i; pthread_t pt; pthread_create(&pt, NULL, thread_func, NULL); pthread_cancel(pt); // 생성된 쓰레드 pt 에 취소 요청을 보낸다. for ( i= 0 ; i< 5 ; i++) { // 5 번 1 초마다 시그널을 보낸다. 바로 cancel 되면 이 signal 을 받을 수 없다. sleep(1); pthread_cond_signal(&cond); } pthread_join(pt, NULL); // join 후 종료한다. printf("exit\n");exit(1); }
Example 5 void clean_up(void *arg) { // 쓰레드 종료시 효출될 함수 여기에 자원해제루틴을 입력할 수 있을 것이다. printf("Thread cancel Clean_up function\n"); } void *thread_func(void *arg) { int i; // DISABLE 상태다. 이경우 쓰레드에 대해서 취소 요청이 들어오면 바로 취소된다. pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); // pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_cleanup_push(clean_up, (void *)NULL); // 쓰레드 종료시 호출될 함수 등록 for(i =0 ; i < 5 ; i++) { pthread_mutex_lock(&lmu); printf("THREAD cond wait\n"); pthread_cond_wait(&cond, &lmu); printf("NO WAIT COND\n"); pthread_mutex_unlock(&lmu); } printf("EXIT\n"); pthread_cleanup_pop(0); }
Example 5 PTHREAD_CANCEL_ENABLE PTHREAD_CANCEL_DISABLE
Thread 의 종류 User-level thread – 커널이 직접 thread 를 스케줄링하지 않고 user mode 에서 라이브러리가 thread 를 스케줄링 – 각 프로세스에 할당되는 time quantum 은 일정하므로 성 능향상이 적다. Kernel-level thread – 커널이 직접 해당 thread 를 스케줄링한다. – 각 thread 에 각각 time quantum 을 할당 –Linux 2.4 (clone() 시스템 콜 ) 이하 및 FreeBSD 등 Combined – 위의 두가지 방식을 복합하여 각각의 thread 들에게 적 당한 time quantum 을 배정 –Solaris 등
Example 6 #include int main() { pthread_attr_t pattr; int scope; pthread_attr_init(&pattr); pthread_attr_setscope(&pattr, PTHREAD_SCOPE_PROCESS); // pthread_attr_setscope(&pattr, PTHREAD_SCOPE_SYSTEM); pthread_attr_getscope(&pattr, &scope); if (scope == PTHREAD_SCOPE_SYSTEM) { printf("user mode thread\n"); } else if (scope == PTHREAD_SCOPE_PROCESS) { printf("Kernel mode thread\n"); } return 1; }
Example 6
Reference Programming with POSIX Threads –Written by Butenhof David R. –Published by Addison-Wesley Professional – erencehttp://joinc.co.kr/modules/moniwiki/wiki.php/article_Pthread_API_Ref erence – C1%A61http://joinc.co.kr/modules/moniwiki/wiki.php/pthread%20%BF%B9% C1%A61 – ellationhttp:// ellation POSIX Threads Programming – MAIN.html#CreatingThreadshttp:// MAIN.html#CreatingThreads Man page about pthread