#include <pthread.h>
#include <unistd.h>
void* func(void* pa)
{
//pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); //允许退出线程
//pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); //设置立即取消
while (1)
{
*(int *)pa+=1;
//pthread_testcancel();
}
return NULL;
}
int main(int argc, char *argv[])
{
int a = 10;
pthread_t thrd;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if ( pthread_create(&thrd, &attr, func, &a))
{
perror( "pthread_create error ");
exit(EXIT_FAILURE);
}
sleep(2);
if (!pthread_cancel(thrd)) //成功则返回0,否则为非0值
{
printf("pthread_cancel OK\n ");
}
while(1){
sleep(1);
printf("a:%d \n", a);
}
sleep(5);
return 0;
}
问题
原因
线程只有运行至Cancelation-point的时候才会退出
Cancelation-point:
线程取消点:
pthread_join()、pthread_testcancel()、pthread_cond_wait()、 pthread_cond_timedwait()、sem_wait()、sigwait()等函数以及read()、write()等会引起阻塞的系 统调用都是Cancelation-point,而其他pthread函数都不会引起Cancelation动作
int pthread_setcancelstate(int state, int *oldstate):
设置本线程对Cancel信号的反应,state有两种值:PTHREAD_CANCEL_ENABLE(缺省)和 PTHREAD_CANCEL_DISABLE,分别表示收到信号后设为CANCLED状态和忽略CANCEL信号继续运行
int pthread_setcanceltype(int type, int *oldtype) :
设置本线程取消动作的执行时机,type由两种取值:PTHREAD_CANCEL_DEFERRED和 PTHREAD_CANCEL_ASYCHRONOUS,仅当Cancel状态为Enable时有效,分别表示收到信号后继续运行至下一个取消点再退出和 立即执行取消动作(退出);
void pthread_testcancel(void) :
检查本线程是否处于Canceld状态,如果是,则进行取消动作,否则直接返回:如果打开第12行就能够退出
思考:
pthread_testcancel();
retcode = read(fd, buffer, length);
pthread_testcancel();
为啥加两个pthread_testcancel();
首 先,取消点并不是为了取消而存在的(pthreadtestcancel除外),它们是等待其他信号的,比如pthread_cond_wait是等待 某个条件的,sem_wait等待一个信号量。它们的共同点是“引起阻塞的系统调用”,在阻塞以后,除了等待的特定信号以外还可以处理一些公共信号,比如 CANCEL信号。接收到特定信号后将恢复线程,而接收到CANCEL信号将退出线程(我理解为一个条件return)。
Read 和Write在POSIX中是标准的取消点,因为它们也进行了“引起阻塞的系统调用”,但是因为Linux自身的问题,没有在这些函数中实现取消点,所以 才需要添加pthread_testcancel来完成POSIX标准,C库函数都没有实现取消点,其他的pthread开头的和 wait结尾的应该都是实现了的。
至于后面也加pthread_testcancel,可能是进入和退出系统调用是两个独立的取消点吧,应对于I/O操作开始后但还未结束时的CANSEL信号,也许只是因为I/O比较费时间所以测试两次:)