有两个线程并没有包含在pthread_attr_t机构中,他们是可取消状态和可取消类型,这两个属性影响着线程在响应
pthread_cancel函数调用时所呈现的行为。
可取消状态属性可以是PTHREAD_CANCEL_ENABLE和PTHREAD_CANCEL_DISABLE,线程可以通过调用
pthread_setcancelstate修改它的可取消状态。
#include<pthread.h> int pthread_setcancelstate(int state, int *oldstate); //成功则返回0,否则返回错误编号。pthread_setcancelstate把当前可取消状态设置为state,把原来的可取消状态存放在oldstate指向的内存单元中,这两
步是原子操作。
pthread_cancel并不等待线程终止,在默认情况下,线程在取消请求发出以后还是继续运行,知道线程到达某个取消点。
取消点是线程检查是否被取消并按照请求进行动作的一个位置。POSIX.1保证在下表中列出的任何函数,取消点都会出现。
下表POSIX.1定义的可选取消点:
线程启动是默认的可取消状态是PTHREAD_CANCEL_ENABLE。当状态设为PTHREAD_CANCEL_DISABLE时,对pthread_cancel的调用并不会杀死
线程,相反,取消请求对这个线程来说处于未决状态。当取消状态再次变成PTHREAD_CANCEL_ENABLE时,线程将在下一个取消点上对所有未决的取消
请求进行处理。
如果应用程序在很长一段时间内都不会调用到上面的函数,那么可以调用pthread_testcancel函数在程序中自己添加取消点。
#include<pthread.h> void pthread_testcancel(void);调用pthread_testcancel时,如果有个取消请求正处于未决状态,而且取消并没有设置为无效,那么线程就会被取消。但是如果
取消被置成无效,pthread_testcancel调用就没有任何效果。
这里所描述的默认取消类型也称为延迟取消,调用pthread_cancel以后,在线程到达取消点之前,并不会出现真正的取消,
可以通过调用pthread_setcanceltype来修改取消类型。
#include<pthread.h> int pthread_setcanceltype(int type, int *oldtype); //成功则返回0,否则返回错误编号。type参数可以是PTHERAD_CANCEL_DEFERRED(延迟取消)或PTHREAD_CANCEL_ASYNCHRONOUS(异步取消),
使用异步取消时,线程可以在任何时间取消,而不是非要等到遇到取消点才能被取消。
实践:
#include <stdio.h> #include <pthread.h> #include <string.h> pthread_t tid1,tid2; void* func1(void* arg){ printf("pause start\n"); sleep(10); printf("pause end\n"); pthread_exit((void*)0); } void* func2(void* arg){ pthread_cancel(tid1); pthread_exit((void*)0); } int main(void){ int err; err = pthread_create(&tid1,NULL,func1,NULL); if(err != 0){ printf("pthread_create:%s\n",strerror(err)); return -1; } sleep(2); err = pthread_create(&tid2,NULL,func2,NULL); if(err != 0){ printf("pthread_create:%s\n",strerror(err)); return -1; } err = pthread_join(tid1, NULL); if(err != 0){ printf("pthread_join:%s\n",strerror(err)); return -1; } err = pthread_join(tid2, NULL); if(err != 0){ printf("pthread_join:%s\n",strerror(err)); return -1; } return 0; }运行结果:
yan@yan-vm:~/apue$ ./a.out
pause start
yan@yan-vm:~/apue$
线程能够在运行pause函数时取消。
我们修改下程序,再运行一下:
#include <stdio.h> #include <pthread.h> #include <string.h> pthread_t tid1,tid2; void* func1(void* arg){ int err; err = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); if(err != 0){ printf("pthread_setcancelstate:%s\n",strerror(err)); pthread_exit((void*)-1); } printf("pause1 start\n"); sleep(10); printf("pause1 end\n"); err = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); if(err != 0){ printf("pthread_setcancelstate:%s\n",strerror(err)); pthread_exit((void*)-1); } printf("pause2 start\n"); pthread_testcancel(); printf("pause2 end\n"); pthread_exit((void*)0); } void* func2(void* arg){ pthread_cancel(tid1); pthread_exit((void*)0); } int main(void){ int err; err = pthread_create(&tid1,NULL,func1,NULL); if(err != 0){ printf("pthread_create:%s\n",strerror(err)); return -1; } sleep(2); err = pthread_create(&tid2,NULL,func2,NULL); if(err != 0){ printf("pthread_create:%s\n",strerror(err)); return -1; } err = pthread_join(tid1, NULL); if(err != 0){ printf("pthread_join:%s\n",strerror(err)); return -1; } err = pthread_join(tid2, NULL); if(err != 0){ printf("pthread_join:%s\n",strerror(err)); return -1; } return 0; }运行结果:
yan@yan-vm:~/apue$ ./a.out
pause1 start
pause1 end
pause2 start
yan@yan-vm:~/apue$
第一次线程为不可取消状态,sleep函数没有被打断。第二次线程为可取消状态,在执行pthread_testcancel函数时被打断,
线程被取消。