pthread中将处理程序送到堆栈上

Posted tianzeng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了pthread中将处理程序送到堆栈上相关的知识,希望对你有一定的参考价值。

pthread_cleanup_push 语法

请使用 pthread_cleanup_push() 将清理处理程序推送到清理栈 (LIFO)。

void pthread_cleanup_push(void(*routine)(void *), void *args);
#include <pthread.h>

/* push the handler "routine" on cleanup stack */

pthread_cleanup_push (routine, arg); 

pthread_cleanup_push 返回值

pthread_cleanup_push() 没有返回值。

void pthread_cleanup_pop(int execute);
#include <pthread.h>



/* pop the "func" out of cleanup stack and execute "func" */

pthread_cleanup_pop (1);



/* pop the "func" and DONT execute "func" */

pthread_cleanup_pop (0); 

如果弹出函数中的参数为非零值,则会从栈中删除该处理程序并执行该处理程序。如果该参数为零,则会弹出该处理程序,而不执行它。

线程显式或隐式调用 pthread_exit(3C) 时,或线程接受取消请求时,会使用非零参数有效地调用 pthread_cleanup_pop()

pthread_cleanup_pop 语法

void pthread_cleanup_pop(int execute);
#include <pthread.h>



/* pop the "func" out of cleanup stack and execute "func" */

pthread_cleanup_pop (1);



/* pop the "func" and DONT execute "func" */

pthread_cleanup_pop (0); 

如果弹出函数中的参数为非零值,则会从栈中删除该处理程序并执行该处理程序。如果该参数为零,则会弹出该处理程序,而不执行它。

线程显式或隐式调用 pthread_exit(3C) 时,或线程接受取消请求时,会使用非零参数有效地调用 pthread_cleanup_pop()

pthread_cleanup_pop 返回值

pthread_cleanup_pop() 没有返回值。

 

解释:

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

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



















































以上是关于pthread中将处理程序送到堆栈上的主要内容,如果未能解决你的问题,请参考以下文章

用完堆内存尝试在 Java 中将单个字符推送到堆栈

访问 linux 线程的本地堆栈(pthreads)

使用片段返回堆栈处理 ActionBar 标题?

恢复片段后android地图停止响应

gcc编译线程程序,为啥要加-lpthread,头文件已经包含了<pthread.h>了啊

gcc编译线程程序,为啥要加-lpthread,头文件已经包含了<pthread.h>了啊