SylixOS中pthread_cancel函数浅析

1 知识简介

1.1 概述

取消一个线程要确保该线程能够释放其所持有的任何锁、分配的内存,使整个系统保持一致性。在很多复杂情况下要保证这种正确性是有一定困难的。

一种简单的线程取消:取消线程调用一个取消线程的函数,被取消线程死亡。在这种情况下,被取消线程所持有的的资源得不到释放。取消线程负责保证被取消者处于可安全取消状态,在一个要求可靠性高的系统中,这种保证非常困难或者无法实现。这种取消称为不受限制的异步取消

还存在另外一种更安全的线程取消机制。一个线程可以以可靠的受控制的方式向进程的其他线程发出取消请求,目标线程可以挂起这一请求使实际的取消动作在此后安全的时候进行,称为延迟取消。目标线程还可以定义其被取消后自动被系统调用的线程清除函数。

SylixOS兼容绝大多数POSIX接口, SylixOS中pthread_cancel函数执行线程取消功能。

pthread_cancel 函数和目标线程的取消动作是异步的。根据目标线程的取消属性不同,取消请求可能被忽略、立即执行或者延迟处理。为了清楚这些动作,下面知识点先简单介绍线程取消属性相关概念。

1.2 知识点

SylixOS中pthread_cancel函数由px_pthread.h头文件定义,其原型为:

int  pthread_cancel (pthread_tthread);

  • 此函数成功返回 0,失败返回错误号;
  • 参数 thread 是取消的线程句柄。

SylixOS中用取消状态,取消类型和取消请求这3个元素共同表示一个线程的取消属性,其存在于线程控制块中。如表2-1所示。

表 2-1  取消说明


表示


说明

取消类型
允许取消

LW_THREAD_CANCEL_ENABLE


线程取消状态决定了指定线程是否可以被取消,取消状态分为允许取消和禁止取消,一个线程设置为允许取消意味着此线程可以被取消,禁止取消意味着此线程只能从自己返回或者调用 pthread_exit函数来退出。


禁止取消

LW_THREAD_CANCEL_DISABLE


取消类型


异步取消

LW_THREAD_CANCEL_ASYNCHRONOUS


取消类型是线程取消的方式,分为异步取消和延迟取消,异步取消属性的线程会在收到取消信号时立即删除自身,也可说成立即取消,延迟取消属性的线程会在“安全”的时机调用线程删除函数删除自身。


延迟取消

LW_THREAD_CANCEL_DEFERRED


取消请求


在延迟取消类型中,取消请求为1表示取消请求被挂起,直到运行到下一个取消点才被执行


该取消请求仅在线程允许取消时可用

线程初始化时会有默认的取消属性,即线程保留允许取消延迟取消的属性,保证收到取消信号时,线程接受该取消信号,不会屏蔽掉,并且会在自身安全的时候,调用线程删除函数,即延迟取消。另外一个线程的取消状态和取消类型可分别调用相关函数设置,如表 2-2所示。函数均在px_pthread.h头文件中定义。

表 2-2  设置取消属性


函数


设置线程取消状态

int

pthread_setcancelstate

(int newstate,  int *poldstate)


设置线程取消类型

int

pthread_setcanceltype

(int newtype,  int *poldtype)


参数


参数 newstate 是新状态

输出参数 poldstate 返回之前的状态


参数 newtype 是新类型

输出参数 poldtype 返回之前的类型


返回值


此函数成功返回 0,失败返回错误号


此函数成功返回 0,失败返回非 0 值

前文提到,延迟请求会使线程的取消动作在安全的时候进行,那线程具体的取消时机是在什么时候呢?会涉及到“取消点”的概念,在后续章节中介绍。

2 技术实现

2.1 实现流程

SylixOS中pthread_cancel函数实现机制,如图3-1所示

图3-1  pthread_cancel函数实现流程

2.2 “取消点”概念

在使用延迟取消机制时,一个线程在可以被取消的地方定义取消点,当收到取消请求时,被取消的线程执行到取消点时退出,或者在一个取消点调用被阻塞时退出。

由于在延迟取消中必须在取消点才能被取消,这一限制可能使取消请求被挂起任意长时间。因此,如果某个调用可能使线程被阻塞或者进入某个较长时间的过程, POSIX 要求这些调用属于一个取消点,或者称这些调用为取消点调用,以防止取消请求陷入长时间等待,SylixOS中存在一些拥有取消点的函数,如open,read,pthread_join,printf等,他们都直接或间接的调用了pthread_testcancel函数pthread_testcancel函数内部实现流程如图 3-2所示。

图 3-2  pthread_testcancel函数实现流程

因此,被取消线程会在执行拥有取消点的函数时,进入到pthread_testcancel函数内部,进行如图 32所示的允许取消、延迟取消以及取消请求标志的判断流程,倘若条件满足,被取消线程会在这里调用线程删除函数删除自身。

表 3-1列出部分拥有取消点的函数以供参考。

表 3-1  拥有取消点的函数


函数名


函数名


函数名


sleep


send


open


system


sendmsg


close


wait


aio_suspend


read


waitid


mq_send


pread


waitpid


mq_receive


write


wait3


pthread_barrier_wait


pwrite


wait4


sem_wait


readv


reclaimchild


tcdrain


writev


accept4


fcntl


fsync


connect


creat


select


recv


sigtimedwait


pause


recvfrom


pthread_join


pthread_testcancel

3 示例演示

以下示例验证均在SylixOS环境下进行。

3.1 示例1:立即取消

如图 4-1所示,子线程设置立即取消类型,那么主线程成功发送取消信号后,打印"pthread_cancel OK",子线程会在下次执行开始处删除自身,退出时子线程i的值可能为0~1000000任意值。

图4-1  立即取消示例

3.2 示例2:延迟取消

如图 4-2所示,子线程设置延迟取消类型,那么主线程执行取消线程函数后,打印“pthread_cancel OK”,子线程会在执行到取消点时删除自身,sleep为拥有取消点的函数,因此子线程退出时i 的值一定为1000000。(即pthread_cancel函数成功返回并不能代表目标线程已经退出)

图 4-2  延迟取消示例

倘若示例1和示例2都把子线程中入口函数中的sleep(1)这条语句去掉,那么示例1中的立即取消仍然有效;示例2中的延迟取消虽然主线程打印“pthread_cancel OK”,但是因为子线程的while(1)循环里没有“取消点”,子线程的取消请求一直都不能被处理,因此子线程并不会被成功取消,而是继续循环运行。如图 4-3所示。

图 4-3 没有“取消点”

不过我们可以手动加入pthread_testcancel函数进行取消请求处理,这样子线程也就有了一个“取消点”,在“取消点”取消请求被处理,线程即可退出。如图 4-4所示。

图 4-4  pthread_testcancel处理取消请求

4 总结

立即取消会通过信号方式修改目标线程任务上下文环境,即把旧目标线程任务上下文做

适当偏移,将信号处理句柄安装在上下文开始处,组成新的目标线程任务上下文,当任务调度轮到目标线程执行时,目标线程会优先执行信号处理程序,完成信号请求的动作。这里要注意时任务调度之后立即取消,因为任务调度切换任务上下文会花费一些时间,所以立即取消并不代表时间上的“立刻”。

延迟取消仅仅使目标线程的线程控制块相关标志修改,在目标线程执行到相关拥有取消点的函数时,进行取消请求检查,满足条件才会删除线程。即任务调度之后,目标线程还会继续执行任务上下文指定任务,直到碰到“取消点”,才可能取消线程。

pthread_cancel的成功返回仅仅表明调用该函数的线程完成了对目标线程线程控制块相关标志的修改,等到任务调度,目标线程才会检查这些标志,做出相应处理,即pthread_cancel的成功返回并不能代表目标线程的完全取消。

由此可见,线程取消并不是安全的,立即取消会让目标线程“立即退出”,延迟取消会给目标线程从开始到“取消点”争取一段执行时间,如果没有“取消点”,目标线程就不能完成预期的线程取消动作,这些都有可能造成很多不安全的因素,目标线程取消之前占有的资源如互斥锁,互斥锁没有释放线程就退出了,将导致别的线程无法获得改锁从而一直阻塞,更严重的还会造成死锁现象。

线程退出时可以调用线程清理处理程序,通过pthread_cleanup_pop和pthread_cleanup_push函数可以将有些“后事”在线程退出后交给线程清理处理程序帮忙处理,本文档此次主要浅析SylixOS的pthread_cancel流程,就不对线程清理处理程序如何使用做详细介绍了。

5 参考资料

SylixOS内核源码

《SylixOS应用程序开发手册》

时间: 2024-09-30 14:47:11

SylixOS中pthread_cancel函数浅析的相关文章

浅析 JavaScript 中的 函数 currying 柯里化

原文:浅析 JavaScript 中的 函数 currying 柯里化 何为Curry化/柯里化? curry化来源与数学家 Haskell Curry的名字 (编程语言 Haskell也是以他的名字命名). 柯里化通常也称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数函数,直至返回最后结果.因此柯里化的过程是逐步传参,逐步缩小函数的适用范围,逐步求解的过程. 柯里化一个求和函数 按照分步求值,我们看一个

javascript中函数浅析

在脚本语言JavaScript中,函数的定义是由事件驱动或者当它被调用时可重复使用的代码块.在JavaScript的标准ECMAscript中,把函数表述为可以随时随地运行的语句.我个人是不认同ECMA的说法的,因为函数只有在发生调用的时候才会执行,否则就是一段毫无生气的代码.我们来具体认识认识函数. (一)首先是函数的定义: 在ECMAscript函数的定义是 关键字function 函数名( 参数){主体:return(返回值)};这四部分组成的,但是在脚本语言中函数的定义却分为三种方式定义

SylixOS线程私有数据浅析

目录 1. 线程私有数据概述    1 2. 线程私有数据的相关API函数流程浅析    1 2.1    加入线程私有变量    1 2.2    删除线程私有变量    3 2.3    设置私有线程变量    6 2.4    获得线程私有变量值    8 3. 总结    10 4. 参考文献    10 线程私有数据概述 在SylixOS中为了满足多线程安全的要求,使得一种资源可以安全的被多个线程使用,采用了包括代码临界区保护和可重入性等方法.本文描述实现可重入的一种方法:线程私有数据

《APUE》中的函数整理

第1章 unix基础知识 1. char *strerror(int errnum) 该函数将errnum(就是errno值)映射为一个出错信息字符串,返回该字符串指针.声明在string.h文件中. 2.void perror(const char *s) 该函数基于当前的errno值,在标准出错文件中输出一条出错消息,然后返回.声明在stdio.h文件中.它首先输出由s指向的字符串,然后是一个冒号,一个空格,接着是errno值对应的出错信息,最后是一个换行符. 第2章 UNIX标准化及实现

linux进程调度函数浅析(基于3.16-rc4)

众所周知,进程调度使用schedule()函数来完成,下面我们从分析该函数开始,代码如下(kernel/sched/core.c): 1 asmlinkage __visible void __sched schedule(void) 2 { 3 struct task_struct *tsk = current; 4 5 sched_submit_work(tsk); 6 __schedule(); 7 } 8 EXPORT_SYMBOL(schedule); 第3行获取当前进程描述符指针,存

[转载]C++虚函数浅析

原文:http://glgjing.github.io/blog/2015/01/03/c-plus-plus-xu-han-shu-qian-xi/ 感谢:单刀土豆 C++虚函数浅析 JAN 3RD, 2015 1:59 AM | COMMENTS 一 引言 C++面向对象语言的一大特性就是抽象,在程序设计上的体现就是鼓励面向接口编程,而不要面向具体实现编程.这里所说的抽象和接口与C++的多态性密切相关.C++的多态分为静态多态(编译时多态)和动态多态(运行时多态)两大类.静态多态通过重载.模

SylixOS中RTC设备驱动

1.概述 本文档基于SylixOS-EVB-i.MX6Q验证平台,介绍SylixOS中RTC设备驱动实现过程,可作为在SylixOS集成开发环境下进行字符设备驱动开发的参考. 2.RTC设备驱动 2.1硬件原理 实时时钟(RTC)的主要功能是在系统掉电的情况下,利用备用电源使时钟继续运行,保证不会丢失时间信息. i.MX6Q验证平台上使用的是外置实时时钟集成电路ISL1208.硬件接线如图 2.1所示. 图 2.1 RTC硬件接线 图中,X1和X2为内部反向放大器的输入和输出引脚,要求外置一个3

SylixOS中DNS静态映射简介

1. DNS功能简介 DNS(Domain Name System,域名系统),因特网上作为域名和IP地址相互映射的一个分布式数据库,用户能够通过域名访问互联网,而不用去记住IP地址.通过域名得到其对应的IP地址的过程叫做域名解析.每个域名都对应一个IP地址,但一个IP地址可以对应多个域名. 2. SylixOS中DNS静态映射 主机名到IP地址的映射有两种方式: 1) 静态映射,每台设备上都配置主机到IP地址的映射,各设备独立维护自己的映射表,而且只供本设备使用: 2) 动态映射,建立一套域名

SylixOS线程堆栈大小浅析

目录 1. SylixOS线程.线程栈介绍    1 1.1    线程的介绍    1 1.2    线程栈的介绍    1 2. SylixOS线程栈大小的分配    1 2.1    线程.线程栈相关属性的设置    2 2.2    线程栈大小    2 2.3    线程堆栈警戒区    3 3. 总结    5 4. 参考资料    5 SylixOS线程.线程栈介绍 SylixOS是多线程操作系统,系统能够同时创建多个线程,具体最大线程数量取决于系统内存的大小以及编译SylixOS