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

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的内存未完成清理。

你可能感兴趣的:(线程)