免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 17628 | 回复: 14
打印 上一主题 下一主题

关于 pthread_cleanup_push 的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-11-13 11:59 |只看该作者 |倒序浏览
关于 pthread_cleanup_push 有如下描述:
================================
从pthread_cleanup_push()的调用点到pthread_cleanup_pop()之间的程序段中的终止动作
(包括调用pthread_exit()和取消点终止)都将执行pthread_cleanup_push()所指定的清理函数。
================================
请问其中的“取消点终止”是什么意思?
我尝试了以下的 pthread_cancel(),但并不会触发 clean(),这是为什么?


以下是代码:
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>

void clean(void* p)
{
        printf("clean()\n");
}

void* thread(void* p)
{
        pthread_cleanup_push(clean, NULL);
        //===============================
        printf("thread sleep\n");
        sleep(10);
        printf("thread wake...\n");
        //===============================
        pthread_cleanup_pop(1);
}

int main()
{
        pthread_t        id;
        pthread_create(&id, NULL, thread, NULL);
        printf("main sleep\n");
        sleep(3);
        printf("cancel thread: %u\n", id);
        pthread_cancel(id);
        return 0;
}

==========================
输出:
thread sleep
main sleep
cancel thread: 3085872016
==========================

在 xxx_push() 和 xxx_pop() 之间唯有调用 pthread_exit() 会触发 clean() 函数,
return 也不会,(异常没有试过, 还不会手动抛出异常);


这是一个老问题了,也看到别人问过(比如: http://bbs.chinaunix.net/viewthread.php?tid=456153)
但在网上一直没有找到正式的回答;

论坛徽章:
0
2 [报告]
发表于 2010-01-13 16:08 |只看该作者

回复 #1 chengdot 的帖子

我的理解是 pthread_cancel() 应该在thread函数中调用,
pthread_cleanup_push() installs the cancellation cleanup handler
      routine onto the calling thread's cancellation cleanup stack. This
      handler will be popped from the calling thread's cancellation cleanup
      stack。

论坛徽章:
0
3 [报告]
发表于 2010-01-13 18:59 |只看该作者
帮顶

论坛徽章:
0
4 [报告]
发表于 2010-01-13 19:43 |只看该作者
同顶

论坛徽章:
0
5 [报告]
发表于 2010-01-14 13:19 |只看该作者
mark

论坛徽章:
0
6 [报告]
发表于 2010-09-15 09:13 |只看该作者
本帖最后由 new_new_one 于 2010-09-15 09:26 编辑

顶起来。

首先你必须知道pthread_cleanup_push与pthread_cleanup_pop的目的(作用)是什么。

比如thread1:
执行
pthread_mutex_lock(&mutex);

//一些会阻塞程序运行的调用,比如套接字的accept,等待客户连接
sock = accept(......);            //这里是随便找的一个可以阻塞的接口

pthread_mutex_unlock(&mutex);
这个例子中,如果线程1执行accept时,线程会阻塞(也就是等在那里,有客户端连接的时候才返回,或则出现其他故障),线程等待中......

这时候线程2发现线程1等了很久,不赖烦了,他想关掉线程1,于是调用pthread_cancel()或者类似函数,请求线程1立即退出。

这时候线程1仍然在accept等待中,当它收到线程2的cancel信号后,就会从accept中退出,然后终止线程,注意这个时候线程1还没有执行:
pthread_mutex_unlock(&mutex);
也就是说锁资源没有释放,这回造成其他线程的死锁问题。

所以必须在线程接收到cancel后用一种方法来保证异常退出(也就是线程没达到终点)时可以做清理工作(主要是解锁方面),pthread_cleanup_push与pthread_cleanup_pop就是这样的。

pthread_cleanup_push(some_clean_func,...)
pthread_mutex_lock(&mutex);

//一些会阻塞程序运行的调用,比如套接字的accept,等待客户连接
sock = accept(......);            //这里是随便找的一个可以阻塞的接口

pthread_mutex_unlock(&mutex);
pthread_cleanup_pop(0);
return NULL;
上面的代码,如果accept被cancel后线程退出,会自动调用some_clean_func函数,在这个函数中你可以释放锁资源。如果accept没有被cancel,那么线程继续执行,当pthread_mutex_unlock(&mutex);表示线程自己正确的释放资源了,而执行pthread_cleanup_pop(0);也就是取消掉前面的some_clean_func函数。接着return线程就正确的结束了。

不晓得你明白没,通俗点就是:
pthread_cleanup_push注册一个回调函数,如果你的线程在对应的pthread_cleanup_pop之前异常退出(return是正常退出,其他是异常),那么系统就会执行这个回调函数(回调函数要做什么你自己决定)。但是如果在pthread_cleanup_pop之前没有异常退出,pthread_cleanup_pop就把对应的回调函数取消了,

关于取消点的解释:

比如你执行:
        printf("thread sleep\n");
        sleep(10);
        printf("thread wake...\n");
在sleep函数中,线程睡眠,结果收到cancel信号,这时候线程从sleep中醒来,但是线程不会立刻退出。这是应为pthread与C库方面的原因(具体是啥我也不清楚),pthread的建议是,如果一个函数是阻塞的,那么你必须在这个函数前后建立取消点,比如:
        printf("thread sleep\n");
        pthread_testcancel();
        sleep(10);
        pthread_testcancel();
        printf("thread wake...\n");
这样,就添加了两个取消掉。在执行到pthread_testcancel的位置时,线程才可能响应cancel退出进程。

额外的知识:
对于cancel信号,线程有两种方法: 忽略,和响应。默认是响应
接收到cancel信号,线程有两种处理类型: 立即响应 和 延迟响应(在最近的取消点响应),默认是延迟响应

论坛徽章:
0
7 [报告]
发表于 2010-09-15 09:30 |只看该作者
至于你的代码例子中为什么没有看到:
printf("clean()\n");
这句的答应结果,是因为你的主线程在执行pthread_cancel后就退出了,这导致进程退出。
换句话说就是你的:printf("clean()\n");还没来得及执行,进程就释放了资源。

你在执行pthread_cancel后在加上一个sleep就行了

论坛徽章:
0
8 [报告]
发表于 2010-09-17 15:01 |只看该作者
学习了。

论坛徽章:
0
9 [报告]
发表于 2011-01-12 14:59 |只看该作者
学习到了

论坛徽章:
0
10 [报告]
发表于 2011-01-13 22:28 |只看该作者
回复 6# new_new_one


    学习聊,谢谢
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP