zoukankan      html  css  js  c++  java
  • 第9章 线程编程(3)_线程清理和控制函数

    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
    ", 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
    ", 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!
    ", th1);
        
        if((err = pthread_create(&th2, NULL, th_fun, (void*)0))){
            perror("pthread_create error");
        }
        pthread_join(th2, NULL);
        printf("th2(%lx) finished!
    ", 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可以使线程进入分离状态。

  • 相关阅读:
    TCP流量控制和拥塞控制
    延迟确认和Nagle算法
    浅谈TCP三次握手和四次挥手
    中介者模式
    代理模式
    装饰者模式
    生成器模式(构建者模式)
    策略模式
    模板方法模式
    抽象工厂模式
  • 原文地址:https://www.cnblogs.com/5iedu/p/6413976.html
Copyright © 2011-2022 走看看