Linux多线程3-5_线程清理操作

简介: 一、概念 1、线程可以安排它退出时的清理操作,这与进程的可以用atexit函数安排进程退出时需要调用的函数类似。这样的函数称为线程清理处理程序。线程      可以建立多个清理处理程序,处理程序记录在栈中,所以这些处理程序执行的顺序与他们注册的顺序相反 pthread_clea...
一、概念
1、线程可以安排它退出时的清理操作,这与进程的可以用atexit函数安排进程退出时需要调用的函数类似。这样的函数称为线程清理处理程序。线程
     可以建立多个清理处理程序,处理程序记录在栈中,所以这些处理程序执行的顺序与他们注册的顺序相反

pthread_cleanup_push(void (*rtn)(void*), void *args)//注册处理程序
pthread_cleanup_pop(int excute)//清除处理程序

2、当执行以下操作时调用清理函数,清理函数的参数由args传入
    1)、调用pthread_exit
    2)、响应取消请求
    3)、用非零参数调用pthread_cleanup_pop

3、清理函数的必要性
    也许你会认为线程不需什么清理操作,我可以在退出之前把所有该办的事情办了。但是,你不能确保你的线程永远正常的退出,加入它被取消呢。
    清理操作的优越性就在于,如果线程被取消了,那么清理函数会自动调用,这一点你是办不到的

4、清理函数要注意
    pthread_cleanup_push()  和 pthread_cleanup_pop() 是用宏定义继承的,宏定义中包含{} ,因此他们两要成对出席那
    
二、手册
PTHREAD_CLEANUP_PUSH(3)    Linux Programmer’s Manual   PTHREAD_CLEANUP_PUSH(3)

NAME
       pthread_cleanup_push, pthread_cleanup_pop - push and pop thread cancellation clean-up handlers
        //注册或者销毁线程取消是的清理函数

SYNOPSIS
       #include
        //包含头文件pthread.h

       void pthread_cleanup_push(void (*routine)(void *),
                                 void *arg);
       void pthread_cleanup_pop(int execute);

       Compile and link with -pthread.
        //编译连接线程库

DESCRIPTION
       These functions manipulate the calling thread’s stack of thread-cancellation clean-up handlers.  A clean-up handler is a
       function that is automatically executed when a thread is canceled (or in various other circumstances  described  below);
       it might, for example, unlock a mutex so that it becomes available to other threads in the process.
        //这两个函数处理线程栈中的取消清理函数。一个清理函数会在线程被取消的时候执行,比如 它可能去解锁一个互斥量
         //让它可以在其他线程中被使用

       The  pthread_cleanup_push()  function  pushes  routine  onto the top of the stack of clean-up handlers.  When routine is
       later invoked, it will be given arg as its argument.
        // pthread_cleanup_push()函数会将它的第一个参数指向的函数压入栈的顶端,当栈顶的函数被唤醒的时候,arg就是它的参数

       The pthread_cleanup_pop() function removes the routine at the top of the stack of clean-up handlers, and optionally exe-
       cutes it if execute is non-zero.
        // The pthread_cleanup_pop()函数将栈顶的清理函数从栈中清除,如果The pthread_cleanup_pop()的参数不是0 的话,清理
        //函数在被取出的时候还会执行


       A cancellation clean-up handler is popped from the stack and executed in the following circumstances:
        //一个取消清理操作会在一下的情况弹出并执行

       1. When  a  thread is canceled, all of the stacked clean-up handlers are popped and executed in the reverse of the order
          in which they were pushed onto the stack.
        //当线程被取消的时候,所有的被压入栈的清理函数都将弹出并执行,他们执行的顺序与入栈的顺序相反

       2. When a thread terminates by calling pthread_exit(3), all clean-up handlers are executed as described in the preceding
          point.  (Clean-up handlers are not called if the thread terminates by performing a return from the thread start func-
          tion.)
        //当一个线程用pthread_exit退出,所有的清理函数回像上面描述的一样执行。如果线程用return返回,那么清理函数不会
         //执行

       3. When a thread calls pthread_cleanup_pop() with a non-zero execute argument, the top-most clean-up handler  is  popped
          and executed.
        //如果线程以非零参数调用 pthread_cleanup_pop(),栈顶的清理函数就会弹出执行

       POSIX.1  permits  pthread_cleanup_push()  and pthread_cleanup_pop() to be implemented as macros that expand to text con-
       taining '{' and '}', respectively.  For this reason, the caller must ensure that calls to  these  functions  are  paired within  the  same
       function,  and at the same lexical nesting level.  (In other words, a clean-up handler is only established during the execution of a
       specified section of code.)
        //在POSIX中,  pthread_cleanup_push()  和 pthread_cleanup_pop() 是用宏定义继承的,宏定义中包含{}。因此要确保这两个函数
         //是成对调用的


       Calling longjmp(3) (siglongjmp(3)) produces undefined results if any call has been  made  to  pthread_cleanup_push()  or
       pthread_cleanup_pop()  without  the  matching  call  of  the  pair  since  the  jump  buffer  was  filled  by  setjmp(3)
       (sigsetjmp(3)).  Likewise, calling longjmp(3) (siglongjmp(3)) from inside a clean-up handler produces undefined  results
       unless the jump buffer was also filled by setjmp(3) (sigsetjmp(3)) inside the handler.
        //在清理函数中调用longjmp或者siglongjmp都会产生未知的结果,除非他们和setjmp或者sigsetjmp成对的出现

RETURN VALUE
       These functions do not return a value.
         //这两个函数没有返回值

ERRORS
       There are no errors.
        //没有错误码

CONFORMING TO
       POSIX.1-2001.

NOTES
       On  Linux,  the pthread_cleanup_push() and pthread_cleanup_pop() functions are implemented as macros that expand to text
       containing '{' and '}', respectively.  This means that variables declared within the scope  of  paired  calls  to  these functions will
       only be visible within that scope.
         //在Linux中,  pthread_cleanup_push()  and pthread_cleanup_pop() 是用宏定义继承的,宏定义中包含{}。因此要确保这两个函数
         //是成对调用的

       POSIX.1  says  that  the  effect  of  using  return,  break,  continue,  or  goto to prematurely leave a block bracketed
       pthread_cleanup_push() and pthread_cleanup_pop() is undefined.  Portable applications should avoid doing this.

四、实例
return返回的线程不会执行清理操作,以非0参数调用pthread_cleanup_pop或者用pthread_exit退出的线程会执行清理操作

点击(此处)折叠或打开

/*DATE:            2015-4-1
 *AUTHOR:        WJ
 *DESCRIPTION:    线程清理处理程序
 *    pthread_cleanup_push(void (*rtn)(void*), void *args)//注册处理程序
 *    pthread_cleanup_pop(int excute)//清除处理程序
 *
 *    这两个函数要成对的出现,否则编译无法通过
 *
 *    当执行以下操作时调用清理函数,清理函数的参数由args传入
 *    1、调用pthread_exit
 *    2、响应取消请求(请你来验证)
 *    3、用非零参数调用pthread_cleanup_pop
 */    

#include "apue.h"

void *fisrt_clean(void *arg)
{
    printf("%s fisrt clean\n", arg);
    return(void *)0;
}
void *second_clean(void *arg)
{
    printf("%s second clean\n", arg);
    return(void *)0;
}

void *thread_fun1(void *arg)
{
    printf("new thread 1\n");
    pthread_cleanup_push(fisrt_clean, "thread1");
    pthread_cleanup_push(second_clean, "thread1");

    pthread_cleanup_pop(1);
    pthread_cleanup_pop(0);

    return(void *)1;
}
void *thread_fun2(void *arg)
{
    printf("new thread 2\n");
    pthread_cleanup_push(fisrt_clean, "thread2");
    pthread_cleanup_push(second_clean, "thread2");

    pthread_exit((void *)2);
    pthread_cleanup_pop(0);
    pthread_cleanup_pop(0);

}

int main()
{
    pthread_t tid1, tid2;
    int err;

    err =pthread_create(&tid1, NULL, thread_fun1, NULL);
    if(err != 0)
    {
        printf("create new thread 1failed\n");
        return;
    }
    err =pthread_create(&tid2, NULL, thread_fun2, NULL);
    if(err != 0)
    {
        printf("create new thread 2failed\n");
        return;
    }

    sleep(2);

    return 0 ;
}
练习:当一个线程被取消,清理操作会执行

点击(此处)折叠或打开

/*DATE:            2015-4-1
 *AUTHOR:        WJ
 *DESCRIPTION:    线程清理处理程序
 *    pthread_cleanup_push(void (*rtn)(void*), void *args)//注册处理程序
 *    pthread_cleanup_pop(int excute)//清除处理程序
 *
 *    这两个函数要成对的出现,否则编译无法通过
 *
 *    当执行以下操作时调用清理函数,清理函数的参数由args传入
 *    1、调用pthread_exit
 *    2、响应取消请求
 *    3、用非零参数调用pthread_cleanup_pop
 */    

#include "apue.h"

void *fisrt_clean(void *arg)
{
    printf("%s fisrt clean\n", arg);
    return(void *)0;
}
void *second_clean(void *arg)
{
    printf("%s second clean\n", arg);
    return(void *)0;
}

void *thread_fun1(void *arg)
{
    printf("new thread 1 start\n");
    //设置清理函数
    pthread_cleanup_push(fisrt_clean, "thread1");
    pthread_cleanup_push(second_clean, "thread1");

    //休眠2s,程序回到主线程,让主线程执行取消操作
    sleep(2);

    pthread_cleanup_pop(1);
    pthread_cleanup_pop(0);

    printf("new thread 1 over\n");
    return(void *)1;
}
void *thread_fun2(void *arg)
{
    printf("new thread 2 start\n");
    //设置清理函数
    pthread_cleanup_push(fisrt_clean, "thread2");
    pthread_cleanup_push(second_clean, "thread2");

    //休眠2s,程序回到主线程,让主线程执行取消操作
    sleep(2);

    printf("new thread 2 over\n");
    pthread_exit((void *)2);
    pthread_cleanup_pop(0);
    pthread_cleanup_pop(0);

}

int main()
{
    pthread_t tid1, tid2;
    int err;

    printf("main thread start\n");
    //创造新线程
    err =pthread_create(&tid1, NULL, thread_fun1, NULL);
    if(err != 0)
    {
        printf("create new thread 1failed\n");
        return;
    }
    err =pthread_create(&tid2, NULL, thread_fun2, NULL);
    if(err != 0)
    {
        printf("create new thread 2failed\n");
        return;
    }

    //休眠1s,让新线程设置清理函数
    sleep(1);

    //取消新线程
    printf("main thread about to cancel new thread\n");
    err = pthread_cancel(tid1);
    if(err)
        printf("cancel new thread 1 failed\n");
    err = pthread_cancel(tid2);
    if(err)
        printf("cancel new thread 2 failed\n");

    //等待新线程结束
    printf("wait for new thread over\n");
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);

    printf("main thread over\n");

    return 0 ;
}





相关文章
|
安全 算法 Java
Java 多线程:线程安全与同步控制的深度解析
本文介绍了 Java 多线程开发的关键技术,涵盖线程的创建与启动、线程安全问题及其解决方案,包括 synchronized 关键字、原子类和线程间通信机制。通过示例代码讲解了多线程编程中的常见问题与优化方法,帮助开发者提升程序性能与稳定性。
588 0
|
存储 Linux API
【Linux进程概念】—— 操作系统中的“生命体”,计算机里的“多线程”
在计算机系统的底层架构中,操作系统肩负着资源管理与任务调度的重任。当我们启动各类应用程序时,其背后复杂的运作机制便悄然展开。程序,作为静态的指令集合,如何在系统中实现动态执行?本文带你一探究竟!
【Linux进程概念】—— 操作系统中的“生命体”,计算机里的“多线程”
|
缓存 监控 Linux
Linux系统清理缓存(buff/cache)的有效方法。
总结而言,在大多数情形下你不必担心Linux中buffer与cache占用过多内存在影响到其他程序运行;因为当程序请求更多内存在没有足够可用资源时,Linux会自行调整其占有量。只有当你明确知道当前环境与需求并希望立即回收这部分资源给即将运行重负载任务之前才考虑上述方法去主动干预。
2776 10
|
并行计算 Linux
Linux内核中的线程和进程实现详解
了解进程和线程如何工作,可以帮助我们更好地编写程序,充分利用多核CPU,实现并行计算,提高系统的响应速度和计算效能。记住,适当平衡进程和线程的使用,既要拥有独立空间的'兄弟',也需要在'家庭'中分享和并行的成员。对于这个世界,现在,你应该有一个全新的认识。
549 67
|
Web App开发 缓存 安全
Linux一键清理系统垃圾:释放30GB空间的Shell脚本实战​
这篇博客介绍了一个实用的Linux系统盘清理脚本,主要功能包括: 安全权限检查和旧内核清理,保留当前使用内核 7天以上日志文件清理和系统日志压缩 浏览器缓存(Chrome/Firefox)、APT缓存、临时文件清理 智能清理Snap旧版本和Docker无用数据 提供磁盘空间使用前后对比和大文件查找功能 脚本采用交互式设计确保安全性,适合定期维护开发环境、服务器和个人电脑。文章详细解析了脚本的关键功能代码,并给出了使用建议。完整脚本已开源,用户可根据需求自定义调整清理策略。
1541 1
|
Java 数据挖掘 调度
Java 多线程创建零基础入门新手指南:从零开始全面学习多线程创建方法
本文从零基础角度出发,深入浅出地讲解Java多线程的创建方式。内容涵盖继承`Thread`类、实现`Runnable`接口、使用`Callable`和`Future`接口以及线程池的创建与管理等核心知识点。通过代码示例与应用场景分析,帮助读者理解每种方式的特点及适用场景,理论结合实践,轻松掌握Java多线程编程 essentials。
948 5
|
数据采集 监控 调度
干货分享“用 多线程 爬取数据”:单线程 + 协程的效率反超 3 倍,这才是 Python 异步的正确打开方式
在 Python 爬虫中,多线程因 GIL 和切换开销效率低下,而协程通过用户态调度实现高并发,大幅提升爬取效率。本文详解协程原理、实战对比多线程性能,并提供最佳实践,助你掌握异步爬虫核心技术。
|
Linux
Linux编程: 在业务线程中注册和处理Linux信号
通过本文,您可以了解如何在业务线程中注册和处理Linux信号。正确处理信号可以提高程序的健壮性和稳定性。希望这些内容能帮助您更好地理解和应用Linux信号处理机制。
423 26
|
Python
python3多线程中使用线程睡眠
本文详细介绍了Python3多线程编程中使用线程睡眠的基本方法和应用场景。通过 `time.sleep()`函数,可以使线程暂停执行一段指定的时间,从而控制线程的执行节奏。通过实际示例演示了如何在多线程中使用线程睡眠来实现计数器和下载器功能。希望本文能帮助您更好地理解和应用Python多线程编程,提高程序的并发能力和执行效率。
683 20
|
Linux
Linux编程: 在业务线程中注册和处理Linux信号
本文详细介绍了如何在Linux中通过在业务线程中注册和处理信号。我们讨论了信号的基本概念,并通过完整的代码示例展示了在业务线程中注册和处理信号的方法。通过正确地使用信号处理机制,可以提高程序的健壮性和响应能力。希望本文能帮助您更好地理解和应用Linux信号处理,提高开发效率和代码质量。
393 17

热门文章

最新文章