pthread中取消线程

取消线程

取消操作允许线程请求终止其所在进程中的任何其他线程。不希望或不需要对一组相关的线程执行进一步操作时,可以选择执行取消操作。

取消线程的一个示例是异步生成取消条件,例如,用户请求关闭或退出正在运行的应用程序。另一个示例是完成由许多线程执行的任务。其中的某个线程可能最终完成了该任务,而其他线程还在继续运行。由于正在运行的线程此时没有任何用处,因此应当取消这些线程。

取消点

仅当取消操作安全时才应取消线程。pthreads 标准指定了几个取消点,其中包括:

  • 通过 pthread_testcancel 调用以编程方式建立线程取消点。

  • 线程等待 pthread_cond_wait 或 pthread_cond_timedwait(3C) 中的特定条件出现。

  • 被 sigwait(2) 阻塞的线程。

  • 一些标准的库调用。通常,这些调用包括线程可基于其阻塞的函数。有关列表,请参见 cancellation(5) 手册页。

缺省情况下将启用取消功能。有时,您可能希望应用程序禁用取消功能。如果禁用取消功能,则会导致延迟所有的取消请求,直到再次启用取消请求。

有关禁用取消功能的信息,请参见pthread_setcancelstate 语法

放置取消点

执行取消操作存在一定的危险。大多数危险都与完全恢复不变量和释放共享资源有关。取消线程时一定要格外小心,否则可能会使互斥保留为锁定状态,从而导致死锁。或者,已取消的线程可能保留已分配的内存区域,但是系统无法识别这一部分内存,从而无法释放它。

标准 C 库指定了一个取消接口用于以编程方式允许或禁止取消功能。该库定义的取消点是一组可能会执行取消操作的点。该库还允许定义取消处理程序的范围,以确保这些处理程序在预期的时间和位置运行。取消处理程序提供的清理服务可以将资源和状态恢复到与起点一致的状态。

必须对应用程序有一定的了解,才能放置取消点并执行取消处理程序。互斥肯定不是取消点,只应当在必要时使之保留尽可能短的时间。

请将异步取消区域限制在没有外部依赖性的序列,因为外部依赖性可能会产生挂起的资源或未解决的状态条件。在从某个备用的嵌套取消状态返回时,一定要小心地恢复取消状态。该接口提供便于进行恢复的功能:pthread_setcancelstate(3C) 在所引用的变量中保留当前的取消状态,pthread_setcanceltype(3C) 以同样的方式保留当前的取消类型。

在以下三种不同的情况下可能会执行取消操作:

  • 异步

  • 执行序列中按标准定义的各个点

  • 调用 pthread_testcancel() 时

缺省情况下,仅在 POSIX 标准可靠定义的点执行取消操作。

无论何时,都应注意资源和状态恢已复到与起点一致的状态

pthread_setcancelstate 语法

int	pthread_setcancelstate(int state, int *oldstate);
#include <pthread.h>

int oldstate;

int ret;

/* enabled */

ret = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);


/* disabled */

ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);

pthread_setcancelstate 返回值

pthread_setcancelstate() 在成功完成之后返回零。其他任何返回值都表示出现了错误。如果出现以下情况,pthread_setcancelstate() 函数将失败并返回相应的值

EINVAL

描述:

状态不是 PTHREAD_CANCEL_ENABLE 或 PTHREAD_CANCEL_DISABLE

pthread_setcanceltype 语法

int	pthread_setcanceltype(int type, int *oldtype);
#include <pthread.h>

int oldtype;

int ret;

/* deferred mode */

ret = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype);

/* async mode*/

ret = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype);

创建线程时,缺省情况下会将取消类型设置为延迟模式。在延迟模式下,只能在取消点取消线程。在异步模式下,可以在执行过程中的任意一点取消线程。因此建议不使用异步模式。

pthread_setcanceltype 返回值

pthread_setcanceltype() 在成功完成之后返回零。其他任何返回值都表示出现了错误。如果出现以下情况,该函数将失败并返回对应的值。

EINVAL

描述:

类型不是 PTHREAD_CANCEL_DEFERRED 或 PTHREAD_CANCEL_ASYNCHRONOUS

pthread_testcancel 语法

void pthread_testcancel(void);
#include <pthread.h>


pthread_testcancel(); 

当线程取消功能处于启用状态且取消类型设置为延迟模式时,pthread_testcancel() 函数有效。如果在取消功能处于禁用状态下调用 pthread_testcancel(),则该函数不起作用。

请务必仅在线程取消操作安全的序列中插入 pthread_testcancel()。除通过 pthread_testcancel() 调用以编程方式建立的取消点以外,pthread 标准还指定了几个取消点。有关更多详细信息,请参见取消点

pthread_testcancel 返回值

pthread_testcancel() 没有返回值。

解释:
有两个线程T1,T2,都要调用fun()函数,函数内容为:fun()
{
int len;

...
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,&iOldState);
pthread_testcancel();
len=read(...);

pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,&iOldState);
...
}
pthread_setcancelstate()函数只是改变本线程(注意是本线程)的cancel state。所以T1进入fun()函数,
执行到pthread_setcancelstate()函数时,只是改变了T1本身的cancel state,并不能改变T2的cancel state。   线程执行到pthread_testcancel()函数时,并不一定会马上取消(退出)。
  描述一下取消一个线程的过程: 1) 其他线程通过调用pthread_cancel()函数,向目标线程发送取消请求(cancellation request)。 2) 取消请求发出后,根据目标线程的cancel state来决定取消请求是否会到达目标线程: a. 如果目标线程的cancel state是PTHREAD_CANCEL_ENABLE(默认),取消请求会到达目标线程。 b. 如果目标线程的cancel state是PTHREAD_CANCEL_DISABLE,取消请求会被放入队列。直到目标线程的cancel state变为PTHREAD_CANCEL_ENABLE,取消请求才会从队列里取出,发到目标线程。 3) 取消请求到达目标线程后,根据目标线程的cancel type来决定线程何时取消: a. 如果目标线程的cancel type是PTHREAD_CANCEL_DEFERRED(默认),目标线程并不会马上取消,而是在执行下一条cancellation point的时候才会取消。有很多系统函数都是cancellation point,详细的列表可以在Linux上用man 7 pthreads查看。除了列出来的cancellation point,pthread_testcancel()也是一个cancellation point。就是说目标线程执行到pthread_testcancel()函数的时候,如果该线程收到过取消请求,而且它的cancel type是PTHREAD_CANCEL_DEFERRED,那么这个线程就会在这个函数里取消(退出),这个函数就不再返回了,目标线程也没有了。 b. 如果目标线程的cancel type是PTHREAD_CANCEL_ASYNCHRONOUS,目标线程会立即取消(这里的“立即”只是说目标线程不用等执行到属于cancellation point的函数的时候才会取消,它会在获得调度之后立即取消,因为内核调度会有延时,所以并不能保证时间上的“立即”)。   举个例子,说明一下这些与线程取消相关的函数的用法:
void thread_function(void *arg)
{
/**
* 线程准备执行一些关键工作,在这个过程中不希望被取消。
* 所以先通过pthread_setcancelstate()将本线程的cancel state
* 设为disabled。
*/
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
/* 执行关键工作 */
...
/**
* 关键工作执行完成,可以被取消。
* 通过pthread_setcancelstate()将本线程的cancel state
* 设为enabled。
*/
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
/**
* 调用pthread_testcancel()函数,检查一下在cancel state
* 为disabled状态的时候,是否有取消请求发送给本线程。
* 如果有的话就取消(退出)。
*/
pthread_testcancel();
/**
* pthread_testcancel()返回了,表明之前没有取消请求发送给本线程,
* 继续其余的工作。
* 这时候如果有取消请求发送给本线程,会在下一次执行到
* cancellation point的时候(例如sleep(), read(), write(), ...)时取消。
*/
...
/**
* 从这里开始,函数里不再包含cancellation point了。
* 如果收到取消请求,将无法取消。所以先把本线程的cancel type
* 设为asynchronous,收到取消请求将立即取消。
*/
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
/* 不包含cancellation point的代码 */
...
}

pthread_testcancel()函数一方面可以用来使LinuxThread与POSIX一致;另一方面就是如果线程函数里没有作为取消点的函数,就可以用pthread_testcancel()人为地创建取消点,使得该线程一旦收到取消请求就可以被取消。

猜你喜欢

转载自www.cnblogs.com/tianzeng/p/9195091.html