1. #include <pthread.h>
  2. #include <unistd.h>
  3. void* func(void* pa)
  4. {
  5. //pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); //允许退出线程
  6. //pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); //设置立即取消
  7. while (1)
  8. {
  9. *(int *)pa+=1;
  10. //pthread_testcancel();
  11. }
  12. return NULL;
  13. }
  14. int main(int argc, char *argv[])
  15. {
  16. int a = 10;
  17. pthread_t thrd;
  18. pthread_attr_t attr;
  19. pthread_attr_init(&attr);
  20. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  21. if ( pthread_create(&thrd, &attr, func, &a))
  22. {
  23. perror( "pthread_create error ");
  24. exit(EXIT_FAILURE);
  25. }
  26. sleep(2);
  27. if (!pthread_cancel(thrd)) //成功则返回0,否则为非0值
  28. {
  29. printf("pthread_cancel OK\n ");
  30. }
  31. while(1){
  32. sleep(1);
  33. printf("a:%d \n", a);
  34. }
  35. sleep(5);
  36. return 0;
  37. }

问题

上面程序并不会将子线程取消,why?

原因

线程只有运行至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比较费时间所以测试两次:)