您的位置:首页 > 运维架构

pthread_cleanup_push()/pop()线程终止清理

2016-02-01 22:07 274 查看

pthread_cleanup_push()和pthread_cleanup_pop()

线程为了访问临界共享资源而为其加上锁,但在访问过程中该线程被外界取消,或者发生了中断,则该临界资源将永远处于锁定状态得不到释放。外界取消操作是不可预见的,因此的确需要一个机制来简化用于资源释放的编程。

在POSIX线程API中提供了一个
pthread_cleanup_push()/pthread_cleanup_pop()
函数对用于自动释放资源–从
pthread_cleanup_push()
的调用点到
pthread_cleanup_pop()
之间的程序段中的终止动作都将执行
pthread_cleanup_push()
所指定的清理函数。

API定义如下:

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


pthread_cleanup_push()/pthread_cleanup_pop()
采用先入后出的栈结构管理

void routine(void *arg)
函数在调用
pthread_cleanup_push()
时压入清理函数栈,多次对
pthread_cleanup_push()
的调用将在清理函数栈中形成一个函数链,在执行该函数链时按照压栈的相反顺序弹出。
execute
参数表示执行到
pthread_cleanup_pop()
时是否在弹出清理函数的同时执行该函数,为0表示不执行,非0为执行;这个参数并不影响异常终止时清理函数的执行。

pthread_cleanup_push()/pop()以宏方式实现

这是
pthread.h
中的宏定义:

#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_pop
的参数
execute
如果为非0值,则按栈的顺序注销掉一个原来注册的清理函数,并执行该函数;

pthread_cleanup_pop()
函数的参数为0时,仅仅在线程调用
pthread_exit
函数或者其它线程对本线程调用
pthread_cancel
函数时,才在弹出“清理函数”的同时执行该“清理函数”。

程序实例

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

/*释放内存*/
void free_mem(void *arg)
{
free(arg);
printf("clean up the memory!\n");
}
/*线程函数*/
void *my_fun(void *arg)
{
char *p = (char*)malloc(10);/*线程函数分配了内存*/
pthread_cleanup_push(free_mem, p);

int i = 0;
for(i = 0;i<10;i++){
printf("this is myfun\n");
sleep(1);
}
pthread_exit((void*)3);/*退出当前线程*/
pthread_cleanup_pop(0);
}

int main()
{
pthread_t ptid;
pthread_create(&ptid, NULL, my_fun, NULL);
int i;
for(i = 1; i < 5; i++ ){
printf("hey naive\n");
sleep(1);
if(i % 3 == 0){
pthread_cancel(ptid);
//i=3时将导致线程函数直接退出,将不会释放my_fun中的malloc的内存
//使用pthread_cleanup_push/pop释放
}
}

int ret;
pthread_join(ptid, (void**)&ret);
printf("return value is : %d\n", ret);

return 0;
}


程序执行结果:

hey naive
this is myfun
hey naive
this is myfun
hey naive
this is myfun
hey naive
clean up the memory!
return value is : -1


若不加
pthread_cleanup_push/pop
释放,将不会打印
clean up the memory!
即对线程函数
malloc
的内存未完成清理。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: