Chinaunix首页 | 论坛 | 博客
  • 博客访问: 349441
  • 博文数量: 161
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 345
  • 用 户 组: 普通用户
  • 注册时间: 2013-12-13 11:04
文章分类

全部博文(161)

文章存档

2015年(15)

2014年(144)

2013年(2)

我的朋友

分类: LINUX

2014-11-11 16:10:54

原文地址:线程取消 作者:xiaozhu2007

1.Pthreads支持3种取消模式,分别为:off(关),deferred(推迟),asynchronous(异步).模式是两位二进制编码,分别是“取消状态”和“取消类型”,每种模式实际上包含开和关两种状态。

模式                    状态         类型               含义

off                    禁用         两者之一      取消Pending被推迟直到启用取消模式

deferred               启用         推迟         在下一个取消点执行取消

asynchronous           启用         异步         可以随时执行取消


默认情况下,取消被推迟执行,并且仅仅能在程序中特定的点被执行,该点检查线程是否被要求终止,被称为取消点。
可能等待一个无界时间的大多数函数应该称为被推迟取消点,推迟的取消点包括等待条件变量,读写文件,以及线程可能被阻塞一段可观的时间的其它函数。
pthread_testcancel的特殊函数,该函数仅仅是一个推迟的取消点,如果线程没被要求终止,它很快会返回,这允许你将任何函数转变为取消点。

The pthread_testcancel() function shall create a cancellation point in the calling thread. The pthread_testcancel() function shall  have  no  effect  if
cancelability is disabled.


如果线程有一个异步取消类型集,或当线程下次到达一个被推迟的取消点时,取消请求将被系统释放。当发生这种情况,系统将设置线程的取消类型是PTHREAD_CANCEL_DELIVEROD,取消状态为PTHREAD_CANCEL_DISABLE。即,线程能清理并终止自己,而不必担心再次被取消。

当作为一个取消点的函数检测到一个未解决的取消请求时,函数将不返回调用者。如果有任何活跃的清除函数,就调用它们,线程终止。没有办法在处理取消并继续执行----线程必须被终止,或者被彻底推迟取消。

如果线程取消的"取消状态"被关闭的话,这个时候请求取消一个线程,则线程记得它被取消但不会采取任何动作,直到“取消状态”被重新启用,因为启用“取消状态”操作不是一个取消点,如果希望未被解决的取消请求能够被立刻处理,需要测试未解决的取消请求(pthread_testcancel).

关于pthread_textcancel的实例:

#include "errors.h"

int count;

void *thread_routine(void *arg)
{

        int            type;
        DPRINTF(("thread_routine starting\n"));

//pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &type);
        for(count = 0; ; count++){
                if(count % 1000 == 0){
                        DPRINTF(("calling testcancel\n"));
                        pthread_testcancel();
                }
        }
}

int main(int argc, char **argv)
{
        int status = 0;
        pthread_t thread_id;
        void *result = NULL;

        pthread_setconcurrency(2);

        status = pthread_create(&thread_id, NULL, thread_routine, NULL);
        if(status != 0){
                err_abort(status, "create thread_routine");
        }

        sleep(2);
        DPRINTF(("calling cancel\n"));

        status = pthread_cancel(thread_id);
        if(status != 0){
                err_abort(status, "cancel thread_id");
        }

        DPRINTF(("calling join\n"));
        status = pthread_join(thread_id, &result);
        if(status != 0){
                err_abort(status, "join thread_id");
        }

        if(result == PTHREAD_CANCELED){
                printf("thread canceled at iteration %d\n", count);
        }
        else{
                printf("thread was not canceled\n");
        }

        exit(0);
}


关于线程取消默认的“取消状态”和“取消模型”,测试代码实例:

#include "../errors.h"

void *thread_routine(void *arg)
{
        int state, type;

        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
        pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &type);

        if(state == PTHREAD_CANCEL_ENABLE){
                printf("Default cancelability state is PTHREAD_CANCEL_ENABLE\n");
        }
        if(type == PTHREAD_CANCEL_DEFERRED){
                printf("Default cancelability type is PTHREAD_CANCEL_DEFERRED\n");
        }

        pthread_setcancelstate(state, &state);
        pthread_setcanceltype(type, &type);
}

int main(int argc, char **argv)
{
        int status = 0;
        pthread_t thread_id;

        status = pthread_create(&thread_id, NULL, thread_routine, NULL);
        if(status != 0){
                err_abort(status, "create thread");
        }

        status = pthread_join(thread_id, NULL);
        if(status != 0){
                err_abort(status, "join thread");
        }

        exit(0);
}

运行结果:

[xxxx@localhost chap5]$ ./a.out
Default cancelability state is PTHREAD_CANCEL_ENABLE
Default cancelability type is PTHREAD_CANCEL_DEFERRED


2.推迟取消:(PTHREAD_CANCEL_ENABLE && PTHREAD_CANCEL_DEFERRED)
线程仅仅到达取消点时才能响应取消请求。
大多数取消点包含可以“无限”时间阻塞线程的I/O操作,它们是可取消的,以便等待能够被打断。

一个例子:

#include "../errors.h"

int count;

void *thread_routine(void *arg)
{
        int state, status;

        for(count = 0; ; count++){
                if((count % 126) == 0){
                        status = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
                        if(status != 0){
                                err_abort(status, "cancel disabled");
                        }
                        sleep(1);
                        status = pthread_setcancelstate(state, &state);
                        if(status != 0){
                                err_abort(status, "cancel enable");
                        }
                }
                else if((count % 1000) == 0){
                        pthread_testcancel();
                }
        }
}

int main(int argc, char **argv)
{
        pthread_t thread_id;
        int status = 0;
        void *result = NULL;

        pthread_setconcurrency(2);
        status = pthread_create(&thread_id, NULL, thread_routine, NULL);
        if(status != 0){
                err_abort(status, "create thread");
        }

        status = pthread_cancel(thread_id);
        if(status != 0){
                err_abort(status, "cancel thread_id");
        }

        status = pthread_join(thread_id, &result);
        if(status != 0){
                err_abort(status, "join thread_id");
        }
        if(result == PTHREAD_CANCELED){
                printf("Thread canceled at iteration %d\n", count);
        }
        else{
                printf("Thread was not canceled\n");
        }

        exit(0);
}


3.异步取消:(PTHREAD_CANCEL_ASYNCHRONOUS && PTHREEAD_CANCEL_ENABLE)
当异步取消被启用时,不允许调用任何能获得资源的函数,除非函数是“异步取消安全”的,否则当异步取消被启用时你不该调用任何函数。
有Pthreads规定的异步取消安全函数是pthread_cancel,pthread_setcancelstate,pthread_setcanceltype(并且当启用异步取消时,没有必要调用pthread_cancel)。

一个例子:

#include "../errors.h"

int a[10][10], b[10][10], c[10][10];

void *thread_routine(void *arg)
{
        int i, j, k, status, type;

        for(i = 0; i < 10; i++){
                for(j = 0; j < 10; j++){
                        a[i][j] = i;
                        b[i][j] = j;
                }
        }

        while(1){
                status = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &type);
                if(status != 0){
                        err_abort(status, "set asyn");
                }

                for(i = 0; i < 10; i++){
                        for(j = 0; j < 10; j++){
                                c[i][j] = 0;
                                for(k = 0; k < 10; k++){
                                        c[i][j] += a[i][k] * b[k][j];
                                }
                        }
                }

                status = pthread_setcanceltype(type, &type);
                if(status != 0){
                        err_abort(status, "unset asyn");
                }

                for(i = 0; i < 10; i++){
                        for(j = 0; j < 10; j++){
                                a[i][j] = c[i][j];
                        }
                }
        }
}

int main(int argc, char **argv)
{
        int status = 0;
        pthread_t thread_id;
        void *result = NULL;

        pthread_setconcurrency(2);
        status = pthread_create(&thread_id, NULL, thread_routine, NULL);
        if(status != 0){
                err_abort(status, "create thread_id");
        }

        sleep(1);
        printf("after 1 second\n");
        status = pthread_cancel(thread_id);
        if(status != 0){
                err_abort(status, "cancel thread_id");
        }

        status = pthread_join(thread_id, &result);
        if(status != 0){
                err_abort(status, "join thread_id");
        }

        if(result == PTHREAD_CANCELED){
                printf("Thread was canceled\n");
        }
        else{
                printf("Thread was not canceled\n");
        }

        exit(0);
}


4.清除:
当一段代码段被取消时,需要恢复一些状态,必须使用清除处理器。
当线程在鞥代一个条件变量时被取消,线程将被唤醒,并保持互斥量加锁状态,在线程终止前,需要恢复不变量,并且释放互斥量。
任何线程都可以push和pop清理处理程序:
void pthread_cleanup_push(void (*function)(void *), void *arg);
void pthread_cleanup_pop(int execute);
当:
调用线程被取消(某个线程调用pthread_cancel);
调用线程自愿终止(pthread_exit,或者从自己的线程起始函数返回)。
时调用清理处理程序。
清理处理程序可以恢复任何需要恢复的状态。
pthread_cleanup_pop总是删除调用线程的“取消清理栈”中位于栈顶的函数,且如果execute不为0,就调用该函数(就算线程没被取消,清理处理程序也会被调用)。

]#include "../errors.h"

#define THREADS 5

typedef struct control_tag{
        int count, busy;
        pthread_mutex_t mutex;
        pthread_cond_t cond;
}control_t;

control_t control = {0, 1, PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER};

void cleanup_routine(void *arg)
{
        control_t *st = (control_t *)arg;
        int status;

        st->count--;
        printf("cleanup_routine: count == %d\n", st->count);
        status = pthread_mutex_unlock(&st->mutex);
        if(status != 0){
                err_abort(status, "unlock mutex");
        }
}

void *thread_routine(void *arg)
{
        int status;

        pthread_cleanup_push(cleanup_routine, (void *)&control);

        status = pthread_mutex_lock(&control.mutex);
        if(status != 0){
                err_abort(status, "thread lock mutex");
        }

        control.count++;

        while(control.busy == 1){
                status = pthread_cond_wait(&control.cond, &control.mutex);
                if(status != 0){
                        err_abort(status, "thread wait cond");
                }
        }

        pthread_cleanup_pop(1);
}

int main(int argc, char **argv)
{
        pthread_t thread_id[THREADS];
        int i, status;
        void *result = NULL;

        for(i = 0; i < THREADS; i++){
                status = pthread_create(&thread_id[i], NULL, thread_routine, NULL);
                if(status != 0){
                        err_abort(status, "create thread");
                }
        }

        sleep(2);

        for(i = 0; i < THREADS; i++){
                status = pthread_cancel(thread_id[i]);
                if(status != 0){
                        err_abort(status, "cancel thread");
                }

                status = pthread_join(thread_id[i], &result);
                if(status != 0){
                        err_abort(status, "join thread");
                }

                if(result == PTHREAD_CANCELED){
                        printf("thread %d canceled\n", i);
                }
                else{
                        printf("thread %d was not canceled\n");
                }
        }

        exit(0);
}

运行结果:

[xxxx@localhost chap5]$ ./a.out
cleanup_routine: count == 4
thread 0 canceled
cleanup_routine: count == 3
thread 1 canceled
cleanup_routine: count == 2
thread 2 canceled
cleanup_routine: count == 1
thread 3 canceled
cleanup_routine: count == 0
thread 4 canceled

阅读(841) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~