《UNIX环境高级编程》笔记--线程的取消选项

有两个线程并没有包含在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保证在下表中列出的任何函数,取消点都会出现。

《UNIX环境高级编程》笔记--线程的取消选项_第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函数时被打断,

线程被取消。

你可能感兴趣的:(《UNIX环境高级编程》笔记--线程的取消选项)