POSIX 线程清理函数

POSIX 多线程的 cleanup 函数

控制清理函数的函数有两个,一个是 pthread_cleanup_push(), 用来把清理函数压入栈中,另一个是 pthread_cleanup_pop(), 用来把栈中的函数弹出来。

用这两个函数组合,可以达到在线程退出时,清理线程数据的作用, 例如对 mutex 进行解锁等。

下面是这两个函数的函数原型:

#include<pthread.h>void pthread_cleanup_push(void(*routine)(void*),void*arg);void pthread_cleanup_pop(int execute);//Compile and link with -pthread.

我们先写个简单的例子,感性认识一下这两个函数的作用:

#include<stdio.h>#include<pthread.h>void handlers(void*arg){if(NULL != arg){
        printf("%s() : [%s]\n", __func__,(char*)arg);}else{
        printf("%s()\n", __func__);}}void*
thread_start(void*arg){
    pthread_cleanup_push(handlers,"one");
    pthread_cleanup_push(handlers,"two");
    pthread_cleanup_push(handlers,"thr");
    printf("This is thread [%u]\n",(unsignedint)pthread_self());
    pthread_exit("he~he~");//do something
    pthread_cleanup_pop(1);
    pthread_cleanup_pop(1);
    pthread_cleanup_pop(1);return NULL;}int main(){pthread_t pt;
    pthread_create(&pt, NULL, thread_start, NULL);void*r = NULL;
    pthread_join(pt,&r);if(NULL != r){
        printf("thread return : [%s]\n",(constchar*)r);}return0;}

编译并运行:

Thisis thread [3290769152]
handlers():[thr]
handlers():[two]
handlers():[one]
thread return:[he~he~]

我们在代码里面是按照 one、two、thr 的顺序调用的 pthread_cleanup_push() 函数, 结果在运行后得到的结果中,却看到它们输出的顺序正好倒过来了。 这正是这对函数的性质。

并且这对函数还有一个性质,那就是使用 pthread_cleanup_push() 和 pthread_cleanup_pop() 之间使用 return 的话,会导致之后的 pthread_cleanup_pop() 不起作用。 这是为什么呢?原因是,其实 pthread_cleanup_push() 和 pthread_cleanup_pop() 不是函数, 而是一对宏。

其宏定义在头文件 pthread.h 中可以看到,宏定义如下:

#  define pthread_cleanup_push(routine, arg) \do{                                            __pthread_cleanup_class __clframe (routine, arg)#  define pthread_cleanup_pop(execute) \
    __clframe.__setdoit (execute);                          }while(0)

我们写个更简单的程序,把这两个宏展开后看一看是什么样结果:

代码如下:

#include<stdio.h>#include<pthread.h>void hand(void* arg){
    printf("do nothing");}void*thread_start(void* arg){
    pthread_cleanup_push(hand,"a");
    printf("This is thread [%u]\n",(unsignedint)pthread_self());
    pthread_cleanup_pop(1);return NULL;}int main(){return0;}

编译:

gcc -g -E -o pthread_cleanup_macro.i pthread_cleanup_macro.c

查看 pthread_cleanup_macro.i 的代码:

void hand(void* arg){
    printf("do nothing");}void*thread_start(void* arg){do{__pthread_unwind_buf_t __cancel_buf;void(*__cancel_routine)(void*)=(hand);void*__cancel_arg =("a");int __not_first_call = __sigsetjmp ((struct __jmp_buf_tag *)(void*) __cancel_buf.__cancel_jmp_buf,0);if(__builtin_expect((__not_first_call),0)){ __cancel_routine (__cancel_arg); __pthread_unwind_next (&__cancel_buf);} __pthread_register_cancel (&__cancel_buf);do{;
    printf("This is thread [%u]\n",(unsignedint)pthread_self());do{}while(0);}while(0); __pthread_unregister_cancel (&__cancel_buf);if(1) __cancel_routine (__cancel_arg);}while(0);return((void*)0);}int main(){return0;}

可以看到,thread_start 函数里面的 pthread_cleanup_push() 和 pthread_cleanup_pop() 已经被展开了。我们把 thread_start 函数里面的代码再修饰一下格式,结果如下:

void*thread_start(void* arg){do{__pthread_unwind_buf_t __cancel_buf;void(*__cancel_routine)(void*)=(hand);void*__cancel_arg =("a");int __not_first_call = __sigsetjmp ((struct __jmp_buf_tag *)(void*) __cancel_buf.__cancel_jmp_buf,0);if(__builtin_expect((__not_first_call),0)){
            __cancel_routine (__cancel_arg);
            __pthread_unwind_next (&__cancel_buf);}
        __pthread_register_cancel (&__cancel_buf);do{;
            printf("This is thread [%u]\n",(unsignedint)pthread_self());do{}while(0);}while(0);
        __pthread_unregister_cancel (&__cancel_buf);if(1) __cancel_routine (__cancel_arg);}while(0);return((void*)0);}

可以看到,我们输出线程信息的 printf 语句,被一层层的 do{}while(0) 给包围了。 如果在 pthread_cleanup_push() 和 pthread_cleanup_pop() 之间加一个 return , 那么整个 do{}while(0) 就会被跳出,后面的代码肯定也就不会被执行了。

时间: 2024-10-08 09:46:30

POSIX 线程清理函数的相关文章

有关POSIX线程的函数

(1)创建线程函数: pthread_create(): (2)阻塞等待线程结束并回收资源函数: pthread_join(): (3)线程退出函数:pthread_exit(); (4)线程互斥锁: 初始化  pthread_mutex_init(); 上锁    pthread_mutex_lock(): 解锁    pthread_mutex_unlock(): (5)线程信号量: 初始化  sem_init():  P操作  sem_wait():   V操作  sem_post():

Linux的POSIX线程属性

创建POSIX线程的函数为 int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); 第1个参数为线程句柄(类似于文件描述符),第3个参数为线程启动函数(输入void*.返回void*,因为指向任何结构体/基本数据类型的指针都可以被看作void*,而void*一般都可以显式强制转换成指向对应类型的指针甚至整型,这是不支持纯C编程的常见

posix 线程(一):线程模型、pthread 系列函数 和 简单多线程服务器端程序

posix 线程(一):线程模型.pthread 系列函数 和 简单多线程服务器端程序 一.线程有3种模型,分别是N:1用户线程模型,1:1核心线程模型和N:M混合线程模型,posix thread属于1:1模型. (一).N:1用户线程模型 “线程实现”建立在“进程控制”机制之上,由用户空间的程序库来管理.OS内核完全不知道线程信息.这些线程称为用户空间线程.这些线程都工作在“进 程竞争范围”(process contention scope):各个线程在同一进程竞争“被调度的CPU时间”(但

POSIX 线程详解(经典必看)

总共三部分: 第一部分:POSIX 线程详解                                   Daniel Robbins ([email protected]), 总裁/CEO, Gentoo Technologies, Inc.  2000 年 7 月 01 日 第二部分:通用线程:POSIX 线程详解,第 2部分       Daniel Robbins ([email protected]), 总裁/CEO, Gentoo Technologies, Inc.  20

Posix线程编程指南(4)

Posix线程编程指南(4) 杨沙洲 原文地址:http://www.ibm.com/developerworks/cn/linux/thread/posix_threadapi/part4/ 线程终止 这是一个关于Posix线程编程的专栏.作者在阐明概念的基础上,将向您详细讲述Posix线程库API.本文是第四篇将向您讲述线程中止. 线程终止方式 一般来说,Posix的线程终止有两种情况:正常终止和非正常终止.线程主动调用pthread_exit()或者从线程函数中return都将使线程正常退

POSIX线程(二)

一. 线程属性 (1) 初始化与销毁属性 int pthread_attr_init(pthread_attr_t *attr); int pthread_attr_destroy(pthread_attr_t *attr); (2)获取与设置分离属性 int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate); int pthread_attr_getdetachstate(pthread_attr_t *att

Posix线程编程指南(2)

Posix线程编程指南(2) 杨沙洲 原文地址:http://www.ibm.com/developerworks/cn/linux/thread/posix_threadapi/part2/ 线程私有数据 这是一个关于Posix线程编程的专栏.作者在阐明概念的基础上,将向您详细讲述Posix线程库API.本文是第二篇将向您讲述线程的私有数据. 概念及作用 在单线程程序中,我们经常要用到"全局变量"以实现多个函数间共享数据.在多线程环境下,由于数据空间是共享的,因此全局变量也为所有线程

转载:Posix线程编程指南(2)

概念及作用 在单线程程序中,我们经常要用到"全局变量"以实现多个函数间共享数据.在多线程环境下,由于数据空间是共享的,因此全局变量也为所有线程所共有.但有时应用程序设计中有必要提供线程私有的全局变量,仅在某个线程中有效,但却可以跨多个函数访问,比如程序可能需要每个线程维护一个链表,而使用相同的函数操作,最简单的办法就是使用同名而不同变量地址的线程相关数据结构.这样的数据结构可以由Posix线程库维护,称为线程私有数据(Thread-specific Data,或TSD). 回页首 创建

Linux中-POSIX 线程详解

一种支持内存共享的简捷工具   摘自https://www.ibm.com/developerworks/cn/linux/thread/posix_thread1/ 线程是有趣的 了解如何正确运用线程是每一个优秀程序员必备的素质.线程类似于进程.如同进程,线程由内核按时间分片进行管理.在单处理器系统中,内核使用时间分片来模拟线程的并发执行,这种方式和进程的相同.而在多处理器系统中,如同多个进程,线程实际上一样可以并发执行. 那么为什么对于大多数合作性任务,多线程比多个独立的进程更优越呢?这是因