《UNIX环境高级编程》笔记55--线程的取消选项
有两个线程并没有包含在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_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_cancel以后,在线程到达取消点之前,并不会出现真正的取消,
可以通过调用pthread_setcanceltype来修改取消类型。
- #include<pthread.h>
- int pthread_setcanceltype(int type, int *oldtype);
- //成功则返回0,否则返回错误编号。
使用异步取消时,线程可以在任何时间取消,而不是非要等到遇到取消点才能被取消。
实践:
- #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;
- }
[email protected]:~/apue$ ./a.out
pause start
[email protected]:~/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;
- }
[email protected]:~/apue$ ./a.out
pause1 start
pause1 end
pause2 start
[email protected]:~/apue$
第一次线程为不可取消状态,sleep函数没有被打断。第二次线程为可取消状态,在执行pthread_testcancel函数时被打断,
线程被取消。