<312>得到線程退出狀態
函數
#include "myapue.h" #include <pthread.h> void *thr_fn1(void *arg) { printf("thread 1 returning\n"); return((void *)1); } void *thr_fn2(void *arg) { printf("thread 2 returning\n"); pthread_exit((void *)2); } int main(void) { int err; pthread_t tid1, tid2; void *tret; err = pthread_create(&tid1, NULL, thr_fn1, NULL); if(err != 0) err_exit(err, "can't create thread 1"); err = pthread_create(&tid2, NULL, thr_fn2, NULL); if(err != 0) err_exit(err, "can't create thread 2"); err = pthread_join(tid1, &tret); if(err != 0) err_exit(err, "can't join with thread 1"); printf("thread 1 exit code %ld\n", (long)tret); err = pthread_join(tid2, &tret); if(err != 0) err_exit(err, "can't join with thread 2"); printf("thread 2 exit code %ld\n", (long)tret); exit(0); }
(1)spa
int pthread_join(pthread_t thread, void **retval);線程
調用線程將一直阻塞,直到指定的線程調用pthread_exit、從啓動例程中返回或者被取消。
指針
此函數能夠得到線程的退出狀態。code
此函數是一種屏障,容許一個線程等待,直到另外一個線程退出。orm
(2)進程
void pthread_exit(void *retval);內存
(3)資源
單個線程能夠經過3種方式退出:作用域
1)簡單地從啓動例程中返回,返回值是線程的退出碼。
2)線程能夠被同一進程中的其餘線程取消。
3)線程調用pthread_exit。
(4)
進程中的任意線程調用了exit相關函數,整個進程就會終止。
<314>
(1)
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
void pthread_exit(void *retval);
這兩個函數的無類型指針參數能夠傳遞包含複雜信息的結構的地址。但因爲傳遞的是地址,則要注意,這個結構所使用的內存在調用者完成調用之後必須任然有效。
#include "apue.h" #include <pthread.h> struct foo { int a, b, c, d; }; void printfoo(const char *s, const struct foo *fp) { printf("%s", s); printf(" structure at 0x%lx\n", (unsigned long)fp); printf(" foo.a = %d\n", fp->a); printf(" foo.b = %d\n", fp->b); printf(" foo.c = %d\n", fp->c); printf(" foo.d = %d\n", fp->d); } void * thr_fn1(void *arg) { struct foo foo = {1, 2, 3, 4}; printfoo("thread 1:\n", &foo); pthread_exit((void *)&foo); } void * thr_fn2(void *arg) { printf("thread 2: ID is %lu\n", (unsigned long)pthread_self()); pthread_exit((void *)0); } int main(void) { int err; pthread_t tid1, tid2; struct foo *fp; err = pthread_create(&tid1, NULL, thr_fn1, NULL); if (err != 0) err_exit(err, "can't create thread 1"); err = pthread_join(tid1, (void *)&fp); if (err != 0) err_exit(err, "can't join with thread 1"); sleep(1); printf("parent starting second thread\n"); err = pthread_create(&tid2, NULL, thr_fn2, NULL); if (err != 0) err_exit(err, "can't create thread 2"); sleep(1); printfoo("parent:\n", fp); exit(0); }
(2)
此程序中,主線程定義告終構變量fp,結構的內容在線程tid1的棧上分配,但線程tid1退出後這個結構的地址就失效了,因此主線程中在此使用這個變量時,打印的是無效的內容。其內容已被第二個線程tid2的棧覆蓋。
<317>
#include "apue.h" #include <pthread.h> void cleanup(void *arg) { printf("cleanup: %s\n", (char *)arg); } void * thr_fn1(void *arg) { printf("thread 1 start\n"); pthread_cleanup_push(cleanup, "thread 1 first handler"); pthread_cleanup_push(cleanup, "thread 1 second handler"); printf("thread 1 push complete\n"); if (arg) return((void *)1); pthread_cleanup_pop(0); pthread_cleanup_pop(0); return((void *)1); } void * thr_fn2(void *arg) { printf("thread 2 start\n"); pthread_cleanup_push(cleanup, "thread 2 first handler"); pthread_cleanup_push(cleanup, "thread 2 second handler"); printf("thread 2 push complete\n"); if (arg) pthread_exit((void *)2); pthread_cleanup_pop(0); pthread_cleanup_pop(0); pthread_exit((void *)2); } int main(void) { int err; pthread_t tid1, tid2; void *tret; err = pthread_create(&tid1, NULL, thr_fn1, (void *)1); if (err != 0) err_exit(err, "can't create thread 1"); err = pthread_create(&tid2, NULL, thr_fn2, (void *)1); if (err != 0) err_exit(err, "can't create thread 2"); err = pthread_join(tid1, &tret); if (err != 0) err_exit(err, "can't join with thread 1"); printf("thread 1 exit code %ld\n", (long)tret); err = pthread_join(tid2, &tret); if (err != 0) err_exit(err, "can't join with thread 2"); printf("thread 2 exit code %ld\n", (long)tret); exit(0); }
(1)
void pthread_cleanup_push(void (*routine)(void *), void *arg);
此函數用於安排線程清理處理程序。
void pthread_cleanup_pop(int execute);
這兩個函數必須在與線程相同的做用域中以匹配對的形式使用。
(2)
當線程執行如下動做時執行清理函數。
調用pthread_exit時
響應取消請求時。(int pthread_cancel(pthread_t thread);)
用非零execute參數調用pthread_cleanup_pop時。(若是execute設置爲0,清理函數將不被調用)
若是線程是經過從它的啓動例程中返回而終止的話,它的清理處理程序就不會被調用。
(3)
線程的終止狀態會保存直到對該線程調用pthread_join。(pthread_join自動把線程置於分離狀態。若是線程已經被分離,線程的底層存儲資源能夠在線程終止時當即被回收)