浅墨浓香

想要天亮进城,就得天黑赶路。

导航

第9章 线程编程(3)_线程清理和控制函数

Posted on 2017-02-18 20:08  浅墨浓香  阅读(540)  评论(0编辑  收藏  举报

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可以使线程进入分离状态。