线程取消:
取消操作允许线程请求终止其所在进程总的任何其他线程。不需要线程执行进一步操作时,可以选择取消操作。
取消点:
如果线程模式设置的是异步模式的话,那只有到取消点才会取消线程。下面会讲到两种取消方式。
那取消点有哪些呢?
1:通过pthread_testcancel 调用已编程方式建立线程取消点
2:线程等待pthread_cond_wait或pthread_cond_timewait中的特定条件
3:被sigwait(2)阻塞的函数
4:一些标准的库调用。通常这些调用包括线程可基于阻塞的函数
default情况下,会启用取消功能。
POSIX标准中,pthread_join(),pthread_testcancel().pthread_cond_wait(),pthread_cond_timewait(),sem_wait(),sigwait()等函数以及read,write等会引起阻塞的系统调用。
取消线程函数
int pthread_cancel(pthread_t thread);
成功之后返回0,失败返回错误号,错误号说明如下:
ESRCH:没有找到线程ID相对应的线程。
int phread_setcancelstate(int state,int *oldstate);设置本线程对信号的反应:
状态:
PTHREAD_CANCEL_ENABLE 默认,收到cancel信号马上设置退出状态
PTHREAD_CANCEL_DISABLE 很明显不处理cancel
返回值:
成功之后返回0.失败返回错误号,错误号说明如下:
EINVAL:状态不是PTHREAD_CANCEL_ENABLE或者PTHREAD_CANCEL_DISABLE
那取消方式呢?取消方式有两种,当然只有在PTHREAD_CANCEL_ENABLE状态下有效
int pthread_setcanceltype(int type, int *oldtype);
PTHREAD_CANCEL_ASYNCHRONOUS 立即执行取消信号
PTHREAD_CANCEL_DEFERRED 运行到下一个取消点
有什么区别呢?
在延迟模式(PTHREAD_CANCEL_DEFERRED)下,只能在取消点取消线程,在异步模式下,可以在任意一点取消线程,这建立还是用延迟模式
注意:当取消线程后,线程里面的锁可能还没有unlock,那么就会出现死锁的情况,如何避免呢?
这里介绍下清理处理程序,它可以将状态恢复到与起点一致的状态,其中包括清理已分配的资源和恢复不变量。
使用pthread_cleanup_push和pthread_cleanup_pop,
push函数是将处理程序推送到清理栈,执行顺序自然是FIFO
void pthread_cleanup_push(void(*routine)(void *) , void (args);
有了这个清理函数,我们只需要把线程要清理的函数push上去,把unlock放在里面,就不会死锁了,当然之前还要lock一下mutex。
void cleanup(void *arg)
{
pthread_mutex_unlock(&mutex);
}
这里举个取消点的例子:
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
void* thr(void* arg)
{
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL);
while(1)
{
pthread_testcancel();
}
printf("thread is not running\n");
sleep(2);
}
int main()
{
pthread_t tid;
int err;
err = pthread_create(&tid,NULL,thr,NULL);
pthread_cancel(tid);
pthread_join(tid,NULL);
sleep(1);
printf("Main thread exited\n");
return 0;
}