3. 线程清理和控制函数
(1)线程清理函数,线程在退出时需要调用的函数,这与进程在退出时要用atexit注册的函数类似
(2)线程可以创建多个线理清理处理程序(thread cleanup handler)。这些处理程序记录在栈中,也就是执行顺序与它们注册的顺序相反。
头文件 |
#include <pthread.h> |
函数 |
void pthread_cleanup_push(void(*rtn)(void*), void* arg); void pthread_cleanup_pop(int execute); |
返回值 |
成功返回0,否则返回错误编号 |
参数 |
①rtn:清理函数指针 ②arg:调用清理函数传递的参数 ③execute:为1时表示执行线程清理函数,为0时不执行。 |
备注 |
①如果execute为0,清理函数将不被调用。 ②pthread_cleanup_pop将删除上次pthread_cleanup_push调用建立的清理处理程序。 ③pthread_cleanup_push和pthread_cleanup_pop是以宏方式实现的,pthread_cleanup_push()带有一个"{",而pthread_cleanup_pop()带有一个"}",因此这两个函数必须成对出现,且必须位于程序的同一级别的代码段中才能通过编译。 ④pthread_cleanup_push()的调用点到pthread_cleanup_pop()之间的程序段中的终止动作(包括调用 pthread_exit()和pthread_cancel)都将执行pthread_cleanup_push()所指定的清理函数。 |
(3)线程调用清理函数的时机
①调用pthread_exit;(注意,线程函数中调用return返回时,不会执行清理函数!)
②响应pthead_cancel的取消请求
③调用thread_cleanup_pop,并传入非0的execute参数。
【编程实验】线程清理函数
//pthread_clean.c
#include <pthread.h> #include <stdio.h> #include <stdlib.h> //定义线程清理函数 void clean_fun(void* arg) { char* s = (char*)arg; printf("clean_fun: %s\n", s); } //线程函数 void* th_fun(void* arg) { pthread_cleanup_push(clean_fun, "first clean func"); pthread_cleanup_push(clean_fun, "second clean func"); printf("subthread(%lx) running\n", pthread_self()); //使用第1种传参方式:arg参数非0。 if(arg) pthread_exit((void*)2); //触发调用清理函数并从这里返回,后面的 //代码将不被执行。 //if(arg) // return ((void*)1); //return返回不会触发调用清理函数! //注意,pthread_cleanup_pop必须与pthread_cleanup_pop成对出现! //使用第2种传参方式时(arg==NULL). //当使用该方式传参时,表示不希望执行清理函数,所以为pthread_cleanup_pop //传入0,表示只是清除栈顶的清理函数,而不执行这个函数。 pthread_cleanup_pop(0); //后进先去:second pthread_cleanup_pop(0); //first return (void*)0; } int main(void) { int err = 0; pthread_t th1, th2; //创建子线程 if((err = pthread_create(&th1, NULL, th_fun, (void*)1))){ perror("pthread_create error"); } pthread_join(th1, NULL); printf("th1(%lx) finished!\n", th1); if((err = pthread_create(&th2, NULL, th_fun, (void*)0))){ perror("pthread_create error"); } pthread_join(th2, NULL); printf("th2(%lx) finished!\n", th2); return 0; } /*输出结果: [root@bogon]# bin/pthread_clean subthread(b77d0b70) running //线程1,调用了清理函数 clean_fun: second clean func //并且以后进先出的方式调用 clean_fun: first clean func th1(b77d0b70) finished! subthread(b77d0b70) running //线程2:不会调用清理函数 th2(b77d0b70) finished! */
4. 进程、线程启动和终止方式的比较
进程 |
线程 |
描述 |
fork() |
pthread_create() |
创建新的控制流 |
return/exit()/_exit() |
return/pthread_exit() |
从现有控制流中退出 |
wait() |
pthread_join() |
从控制流中得到退出状态 |
getpid |
pthread_self() |
获取控制流ID |
atexit() |
pthread_cleanup_push() pthread_cleanup_pop(); |
注册在退出控制流时调用的函数。 |
abort |
pthread_cancel |
请求控制流的非正常退出 |
【备注】在默认情况下,线程的终止状态会保存到对该线程调用pthread_join,如果线程己经处于分离 状态,线程的终止状态信息可以在线程终止时立即被回收。调用pthread_detach可以使线程进入分离状态。 |