SylixOS中pthread_cancel浅析

1.知识简介

1.1 概述

       取消一个线程要确保该线程可以释放其所持有的任何锁、分配的内存,使整个系统保持一致性。在不少状况下要保证这种正确性是有必定困难的。安全

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

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

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

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

1.2 知识点

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

        int  pthread_cancel (pthread_tthread);进程

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

 

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

表2‑1  取消说明资源

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

表2‑2  设置取消属性

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

2.技术实现

2.1 实现流程

       SylixOS中pthread_cance函数实现机制,如图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函数内部,进行如图 3‑2所示的容许取消、延迟取消以及取消请求标志的判断流程,假若条件知足,被取消线程会在这里调用线程删除函数删除自身。

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

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

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应用程序开发手册》

相关文章
相关标签/搜索