关于 pthread

来源:百度文库 编辑:神马文学网 时间:2024/04/25 12:24:14
chengdot
  • 发短消息
  • 加为好友

chengdot 当前离线

UID
22843309 
帖子
48 
精华
0 
积分
72 
可用积分
72  
信誉积分
100  
专家积分
0  
空间积分
0  
阅读权限
10 
在线时间
101 小时 
注册时间
2009-11-10 
最 后登录
2010-10-09 

侠客

帖子
48 
主题
8 
精华
0 
可用积分
72  
专家积分
0  
在线时间
101 小时 
注册时间
2009-11-10 
最 后登录
2010-10-09 

状态:...当前离线...

[微博] [博客] [短信]

[倒序看帖] 1发表于 2009-11-13 11:59 | 只看该作者

关于 pthread_cleanup_push 有如下描述:
================================
从pthread_cleanup_push()的调用点到pthread_cleanup_pop()之间的程序段中的终止动作
(包括调用pthread_exit()和取消点终止)都将执行pthread_cleanup_push()所指定的清理函数。
================================
请问其中的“取消点终止”是什么意思?
我尝试了以下的 pthread_cancel(),但并不会触发 clean(),这是为什么?


以下是代码:
#include
#include
#include
#include

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)
但在网上一直没有找到正式的回答;

诚邀您共建CU技术主题索引贴| PC采购经济效益如何最佳? | Redhat授权RHCE超低价考试| 《深入理解计算机系统》第2版

yang200218
  • 发短消息
  • 加为好友

yang200218 当前离线

UID
12644448 
帖子
132 
精华
0 
积分
217 
可用积分
217  
信誉积分
0  
专家积分
0  
空间积分
0  
阅读权限
20 
在线时间
199 小时 
注册时间
2008-04-11 
最 后登录
2010-10-09 

圣骑士

帖子
132 
主题
11 
精华
0 
可用积分
217  
专家积分
0  
在线时间
199 小时 
注册时间
2008-04-11 
最 后登录
2010-10-09 

状态:...当前离线...

[微博] [博客] [短信]

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。

诚邀您共建CU技术主题索引贴| PC采购经济效益如何最佳? | Redhat授权RHCE超低价考试| 《深入理解计算机系统》第2版




new_new_one
  • 发短消息
  • 加为好友

new_new_one 当前离线

UID
22315117 
帖子
54 
精华
0 
积分
92 
可用积分
92  
信誉积分
100  
专家积分
0  
空间积分
0  
阅读权限
10 
在线时间
23 小时 
注册时间
2009-08-10 
最 后登录
2010-11-03 

骑士

帖子
54 
主题
16 
精华
0 
可用积分
92  
专家积分
0  
在线时间
23 小时 
注册时间
2009-08-10 
最 后登录
2010-11-03 

状态:...当前离线...

[微博] [博客] [短信]

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信号,线程有两种处理类型: 立即响应 和 延迟响应(在最近的取消点响应),默认是延迟响应

诚邀您共建CU技术主题索引贴| PC采购经济效益如何最佳? | Redhat授权RHCE超低价考试| 《深入理解计算机系统》第2版

new_new_one
  • 发短消息
  • 加为好友

new_new_one 当前离线

UID
22315117 
帖子
54 
精华
0 
积分
92 
可用积分
92  
信誉积分
100  
专家积分
0  
空间积分
0  
阅读权限
10 
在线时间
23 小时 
注册时间
2009-08-10 
最 后登录
2010-11-03 

骑士

帖子
54 
主题
16 
精华
0 
可用积分
92  
专家积分
0  
在线时间
23 小时 
注册时间
2009-08-10 
最 后登录
2010-11-03 

状态:...当前离线...

[微博] [博客] [短信]

7发表于 2010-09-15 09:30 | 只看该作者

至于你的代码例子中为什么没有看到:
printf("clean()\n");
这句的答应结果,是因为你的主线程在执行pthread_cancel后就退出了,这导致进程退出。
换句话说就是你的:printf("clean()\n");还没来得及执行,进程就释放了资源。

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