<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)
int pthread_join(pthread_t thread, void **retval);
调用线程将一直阻塞,直到指定的线程调用pthread_exit、从启动例程中返回或者被取消。
此函数可以获得线程的退出状态。
此函数是一种屏障,允许一个线程等待,直到另一个线程退出。
(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自动把线程置于分离状态。如果线程已经被分离,线程的底层存储资源可以在线程终止时立即被回收)