Linux 线程取消(pthread_cancel)
基本概念
pthread_cancel调用并不等待线程终止,它只提出请求。线程在取消请求(pthread_cancel)发出后会继续运行,直到到达某个取消点(CancellationPoint)。取消点是线程检查是否被取消并按照请求进行动作的一个位置.
与线程取消相关的pthread函数
int pthread_cancel(pthread_t thread)
发送终止信号给thread线程,如果成功则返回0,否则为非0值。发送成功并不意味着thread会终止。
int pthread_setcancelstate(int state, int *oldstate)
设置本线程对Cancel信号的反应,state有两种值:PTHREAD_CANCEL_ENABLE(缺省)和PTHREAD_CANCEL_DISABLE,
分别表示收到信号后设为CANCLED状态和忽略CANCEL信号继续运行;old_state如果不为NULL则存入原来的Cancel状态以便恢复。
int pthread_setcanceltype(int type, int *oldtype)
设置本线程取消动作的执行时机,type由两种取值:PTHREAD_CANCEL_DEFFERED和PTHREAD_CANCEL_ASYCHRONOUS,仅当Cancel状态为Enable时有效,分别表示收到信号后继续运行至下一个取消点再退出和立即执行取消动作(退出);oldtype如果不为NULL则存入运来的取消动作类型值。
void pthread_testcancel(void)
是说pthread_testcancel在不包含取消点,但是又需要取消点的地方创建一个取消点,以便在一个没有包含取消点的执行代码线程中响应取消请求.
线程取消功能处于启用状态且取消状态设置为延迟状态时,pthread_testcancel()函数有效。
如果在取消功能处处于禁用状态下调用pthread_testcancel(),则该函数不起作用。
请务必仅在线程取消线程操作安全的序列中插入pthread_testcancel()。除通过pthread_testcancel()调用以编程方式建立的取消点意外,pthread标准还指定了几个取消点。测试退出点,就是测试cancel信号.
取消点:
线程取消的方法是向目标线程发Cancel信号,但如何处理Cancel信号则由目标线程自己决定,或者忽略、或者立即终止、或者继续运行至Cancelation-point(取消点),由不同的Cancelation状态决定。
线程接收到CANCEL信号的缺省处理(即pthread_create()创建线程的缺省状态)是继续运行至取消点,也就是说设置一个CANCELED状态,线程继续运行,只有运行至Cancelation-point的时候才会退出。
pthreads标准指定了几个取消点,其中包括:
(1)通过pthread_testcancel调用以编程方式建立线程取消点。
(2)线程等待pthread_cond_wait或pthread_cond_timewait()中的特定条件。
(3)被sigwait(2)阻塞的函数
(4)一些标准的库调用。通常,这些调用包括线程可基于阻塞的函数。
缺省情况下,将启用取消功能。有时,您可能希望应用程序禁用取消功能。如果禁用取消功能,则会导致延迟所有的取消请求,
直到再次启用取消请求。
根据POSIX标准,pthread_join()、pthread_testcancel()、pthread_cond_wait()、pthread_cond_timedwait()、sem_wait()、sigwait()等函数以及
read()、write()等会引起阻塞的系统调用都是Cancelation-point,而其他pthread函数都不会引起Cancelation动作。
但是pthread_cancel的手册页声称,由于LinuxThread库与C库结合得不好,因而目前C库函数都不是Cancelation-point;但CANCEL信号会使线程从阻塞的系统调用中退出,并置EINTR错误码,因此可以在需要作为Cancelation-point的系统调用前后调用pthread_testcancel(),从而达到POSIX标准所要求的目标.
即如下代码段:
pthread_testcancel();
retcode = read(fd, buffer, length);
pthread_testcancel();
注意:
程序设计方面的考虑,如果线程处于无限循环中,且循环体内没有执行至取消点的必然路径,则线程无法由外部其他线程的取消请求而终止。因此在这样的循环体的必经路径上应该加入pthread_testcancel()调用.
取消类型(Cancellation Type)
我们会发现,通常的说法:某某函数是 Cancellation Points,这种方法是容易令人混淆的。
因为函数的执行是一个时间过程,而不是一个时间点。其实真正的 Cancellation Points 只是在这些函数中 Cancellation Type 被修改为 PHREAD_CANCEL_ASYNCHRONOUS 和修改回 PTHREAD_CANCEL_DEFERRED 中间的一段时间。
POSIX的取消类型有两种,一种是延迟取消(PTHREAD_CANCEL_DEFERRED),这是系统默认的取消类型,即在线程到达取消点之前,不会出现真正的取消;另外一种是异步取消(PHREAD_CANCEL_ASYNCHRONOUS),使用异步取消时,线程可以在任意时间取消。
线程终止的清理工作
Posix的线程终止有两种情况:正常终止和非正常终止。
线程主动调用pthread_exit()或者从线程函数中return都将使线程正常退出,这是可预见的退出方式;
非正常终止是线程在其他线程的干预下,或者由于自身运行出错(比如访问非法地址)而退出,这种退出方式是不可预见的。
不论是可预见的线程终止还是异常终止,都会存在资源释放的问题,在不考虑因运行出错而退出的前提下,如何保证线程终止时能顺利的释放掉自己所占用的资源,特别是锁资源,就是一个必须考虑解决的问题。
最经常出现的情形是资源独占锁的使用:线程为了访问临界资源而为其加上锁,但在访问过程中被外界取消,如果线程处于响应取消状态,且采用异步方式响应,或者在打开独占锁以前的运行路径上存在取消点,则该临界资源将永远处于锁定状态得不到释放。外界取消操作是不可预见的,因此的确需要一个机制来简化用于资源释放的编程。
在POSIX线程API中提供了一个pthread_cleanup_push()/ pthread_cleanup_pop()函数,
对用于自动释放资源—从pthread_cleanup_push()的调用点到pthread_cleanup_pop()之间的程序段中的终止动作(包括调用pthread_exit()和取消点终止)都将执行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() 的调用将在清理函数栈中形成一个函数链;
从pthread_cleanup_push的调用点到pthread_cleanup_pop之间的程序段中的终止动作(包括调用pthread_exit()和异常终止,不包括return)
都将执行pthread_cleanup_push()所指定的清理函数。
在执行该函数链时按照压栈的相反顺序弹出。execute参数表示执行到 pthread_cleanup_pop()时
是否在弹出清理函数的同时执行该函数,为0表示不执行,非0为执行;这个参数并不影响异常终止时清理函数的执行。
pthread_cleanup_push()/pthread_cleanup_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()带有一个"}",因此这两个函数必须成对出现,且必须位于程序的同一级别的代码段中才能通过编译。
在下面的例子里,当线程在"do some work"中终止时,将主动调用pthread_mutex_unlock(mut),以完成解锁动作。
pthread_cleanup_push(pthread_mutex_unlock, (void*) &mut);
pthread_mutex_lock(&mut);
/* do some work */
pthread_mutex_unlock(&mut);
pthread_cleanup_pop(0);
或者
void cleanup(void *arg)
{
pthread_mutex_unlock(&mutex);
}
void* thread0(void* arg)
{
pthread_cleanup_push(cleanup, NULL); // thread cleanup handler p
thread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
pthread_cleanup_pop(0);
pthread_exit(NULL);
}
Linux 线程取消(pthread_cancel)的更多相关文章
- 线程取消 (pthread_cancel)
线程取消(pthread_cancel) 基本概念pthread_cancel调用并不等待线程终止,它只提出请求.线程在取消请求(pthread_cancel)发出后会继续运行,直到到达某个取消点(C ...
- POSIX 线程取消点的 Linux 实现
http://blog.csdn.net/stevenliyong/article/details/4364039 原文链接:http://blog.solrex.cn/articles/linux- ...
- Linux线程学习(一)
一.Linux进程与线程概述 进程与线程 为什么对于大多数合作性任务,多线程比多个独立的进程更优越呢?这是因为,线程共享相同的内存空间.不同的线程可以存取内存中的同一个变量.所以,程序中的所有线程都可 ...
- Linux线程学习(二)
线程基础 进程 系统中程序执行和资源分配的基本单位 每个进程有自己的数据段.代码段和堆栈段 在进行切换时需要有比较复杂的上下文切换 线程 减少处理机的空转时间,支持多处理器以及减少上下文切换开销, ...
- linux线程(一)基本应用
有感而发(可以直接忽略~):每次要用到线程,都要在网上重新学下基础,例子倒是不少:一种是排版好,讲的不全又不是自己想要的:一种是排版不好,直接略过了.两者兼有的又要苦苦寻找,所以还是自己总结了,觉得每 ...
- pthread_setcanceltype 线程取消
取消线程: (1)一个线程可以调用pthread_cancel来取消另一个线程. (2)被取消的线程需要被join来释放资源. (3)被取消的线程的返回值为PTHREAD_CANCELED ...
- linux线程(一)
线程的优先级无法保障线程的执行次序.只不过优先级高的线程获取 CPU 资源的概率大一点而已. 线程相关函数(1)-pthread_create(), pthread_join(), pthread_e ...
- 三十六、Linux 线程——线程基本概念及线程的创建和终止
36.1 线程介绍 36.1.1 线程的基本概念 进程是资源管理的最小单位,线程是程序执行的最小单位 每个进程都有自己的数据段.代码段和堆栈段. 线程通常叫做轻型的进程,它包含独立的栈和 CPU 寄存 ...
- Linux线程编程之信号处理
前言 Linux多线程环境中的信号处理不同于进程的信号处理.一方面线程间信号处理函数的共享性使得信号处理更为复杂,另一方面普通异步信号又可转换为同步方式来简化处理. 本文首先介绍信号处理在进程中和线程 ...
随机推荐
- 变形和透视 perspective
前面介绍了css3 2D变形(transform)移动.缩放.旋转.倾斜 有2D 也有3D,例如3D transform中有下面这三个方法: rotateX( angle ) rotateY( ang ...
- mvn ssm 异常 org.springframework.beans.factory.BeanCreationException:Error creating bean with name 'multipartResolver'
解决方案: 添加 commons-fileupload-1.2.jar <!-- https://mvnrepository.com/artifact/commons-fileupload/co ...
- Arts打卡第9周
Algorithm.主要是为了编程训练和学习. 每周至少做一个 leetcode 的算法题(先从Easy开始,然后再Medium,最后才Hard). 进行编程训练,如果不训练你看再多的算法书,你依然不 ...
- /dev/mem同步写不能使用msync的MS_SYNC选项探究
问题 做了个测试板子的程序,里面有一项写铁电的功能,要求写入之后立即断电,重启后校验数据准确性:铁电设计是通过内存地址直接映射的,于是,使用mmap直接映射了/dev/mem文件,自然地写入之后使用m ...
- javaWeb项目部署到阿里云服务器
1.云服务器中配置了jdk+eclipse+tomcat 2.将项目导出War到安装的Tomcat的webapps文件夹中: 右击项目->Export->WarFile->Desti ...
- python中的with的用法,上下文管理器
with是从Python2.5引入的一个新的语法,它是一种上下文管理协议,目的在于从流程图中把 try,except 和finally 关键字和 资源分配释放相关代码统统去掉,简化try….excep ...
- Cross-Site Request Forgery (CSRF)
https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF) Overview Cross-Site Request Forger ...
- Java-编程规范与代码风格
阿里巴巴 Java 开发手册 https://github.com/alibaba/p3c https://developer.aliyun.com/special/tech-java 唯品会规范 J ...
- usb 设备 复位
How to Reset USB Device in Linux by ROMAN10 on MAY 4, 2011 · 9 COMMENTS USB devices are anywhere n ...
- 用了pm2之后,如何让console.log('..')出现在控制台
使用 pm2 log 0 可以查看.当然这个 0 应该是应用的 id