诺亚方舟

沉淀

多线程资源回收学习–pthread_cleanup_push/pop

Posix的线程终止有两种情况:正常终止和非正常终止。
线程主动调用pthread_exit()或者从线程函数中return都将使线程正常退出,这是可预见的退出方式;
非正常终止是线程在其他线程的干预下(例如线程取消),或者由于自身运行出错(比如访问非法地址)而退出,这种退出方式是不可预见的。

个人觉得,还有一种,是进程被强制杀死或退出,这种整个进程已经结束,资源会被系统自动回收,因此并没有存在需要回收资源的需求。

不论是可预见的线程终止还是异常终止,都会存在资源释放的问题,在不考虑因运行出错而退出的前提下,如何保证线程终止时能顺利的释放掉自己所占用的资源,特别是锁资源,就是一个必须考虑解决的问题。
最经常出现的情形是资源独占锁的使用:线程为了访问临界资源而为其加上锁,但在访问过程中被外界取消,如果线程处于响应取消状态,且采用异步方式响应,或者在打开独占锁以前的运行路径上存在取消点,则该临界资源将永远处于锁定状态得不到释放。外界取消操作是不可预见的,因此的确需要一个机制来简化用于资源释放的编程。在正常退出状态下,我们可以通过主线程等待子线程,由pthread_join()回收资源,但是异常退出状态则没有办法通过pthread_join()回收,这时候在POSIX线程API中提供了一个pthread_cleanup_push()/ pthread_cleanup_pop()函数,对用于自动释放资源—从pthread_cleanup_push()的调用点到pthread_cleanup_pop()之间的程序段中的终止动作(包括调用pthread_exit()和取消点终止)都将执行pthread_cleanup_push()所指定的清理函数。

pthread_cleanip_push/pop是以宏方式实现的,在pthread.h中的定义:

1
2
3
4
5
6
7
8
#define pthread_cleanup_push(routine,arg) \ 
{ 
struct _pthread_cleanup_buffer _buffer; \ 
_pthread_cleanup_push (&_buffer, (routine), (arg));
 
#define pthread_cleanup_pop(execute) \ 
_pthread_cleanup_pop (&_buffer, (execute)); \
}

可见,pthread_cleanup_push()带有一个”{“,而pthread_cleanup_pop()带有一个”}”,因此这两个函数必须成对出现,且必须位于程序的同一级别的代码段中才能通过编译。

pthread_cleanup_push()/pthread_cleanup_pop()采用先入后出的栈结构管理,在调用pthread_cleanup_push()时压入清理函数栈,多次对pthread_cleanup_push() 的调用将在清理函数栈中形成一个函数链;从pthread_cleanup_push的调用点到pthread_cleanup_pop之间的程序段中的终止动作(包括调用pthread_exit()和异常终止,不包括return)都将执行pthread_cleanup_push()所指定的清理函数。在执行该函数链时按照压栈的相反顺序弹出。execute参数表示执行到 pthread_cleanup_pop()时是否在弹出清理函数的同时执行该函数,为0表示不执行,非0为执行;这个参数并不影响异常终止时清理函数的执行。

个人觉得,pthread_cleanup_push/pop这对函数的使用类似注册的机制,并不像逻辑流处理。

下面是一篇关于pthread_cleanip_push/pop使用的细致介绍:

[Linux]pthread学习笔记

文章参考:线程取消(pthread_cancel)

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>