posix多线程--线程取消

1.三种取消状态
Off                   禁用取消
Deferred           推迟取消:在下一个取消点执行取消
Asynchronous   异步取消:可以随时执行取消

int pthread_cancel(pthread_t thread)

 

2.推迟取消:在下一个取消点执行取消

Pthreads系统上的某些函数会被作为取消点,如pthread_testcancel,sleep,pthread_cond_wait等。
线程调用pthread_cancel函数后,被取消线程不会立即取消,仅仅在到达取消点时响应取消请求。

代码示例如下:

在pthread_testcancel取消点,响应线程取消请求。

#include<stdio.h>                                                                
#include<pthread.h>
#include<errno.h>
int counter;
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
void *thread_route(void *arg)
{
        pthread_mutex_lock(&mutex);
        for(counter=0;;counter++)
        {
                if(counter%2000==0){
                        printf("calling testcancel\n");
                        pthread_testcancel();
                }

        }
        pthread_mutex_unlock(&mutex);
}
int main(void)
{
        pthread_t tid;
        void *result;
        pthread_create(&tid,NULL,thread_route,NULL);
        sleep(1);
        printf("call cancel\n");
        pthread_cancel(tid);
        printf("call joining\n");
        pthread_join(tid,&result);
        if(result==PTHREAD_CANCELED)
        {
            printf("Thread cancelled at %d\n",counter);
        }
        else{
                printf("Thread was not canceled\n");
        }
        pthread_mutex_lock(&mutex);
        printf("main thread locked");
        pthread_mutex_unlock(&mutex);
} 
View Code

 

3.如果要保证取消不在一个特别的取消点发生,可以暂时在代码的那个区域停用取消。
int pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,int *state)

代码示例如下:

在sleep()时,禁用取消。

#include<stdio.h>                                                                
#include<pthread.h>
#include<errno.h>
int counter;
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
void *thread_route(void *arg)
{
        int state;
        pthread_mutex_lock(&mutex);
        for(counter=0;;counter++)
        {
                if(counter%582==0)
                {
                        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,&state)
;
                        sleep(1);
                        pthread_setcancelstate(state,&state);
                }
                if(counter%2000==0){
                        printf("calling testcancel\n");
                        pthread_testcancel();
                }

        }
        pthread_mutex_unlock(&mutex);
}
int main(void)
{
        pthread_t tid;
        void *result;
        pthread_create(&tid,NULL,thread_route,NULL);
        sleep(1);
        printf("call cancel\n");
        pthread_cancel(tid);
        printf("call joining\n");
        pthread_join(tid,&result);
        if(result==PTHREAD_CANCELED)
        {
                printf("Thread cancelled at %d\n",counter);
        }
        else{
                printf("Thread was not canceled\n");
        }
        pthread_mutex_lock(&mutex);
        printf("main thread locked");
        pthread_mutex_unlock(&mutex);
}           
View Code

 

4.异步取消:可以随时执行取消
异步取消不需要使用取消点来查询取消请求。异步取消不能获得任何资源,应避免异步的取消
代码示例如下:

矩阵相乘线程取消

#include<stdio.h>                                                                
#include<pthread.h>
#define SIZE 10
int arr_a[SIZE][SIZE];
int arr_b[SIZE][SIZE];
int arr_c[SIZE][SIZE];
void printarr(int arr[SIZE][SIZE])
{
        int i,j;
        for(i=0;i<SIZE;i++)
        {
                for(j=0;j<SIZE;j++)
                {
                        printf("%x ",arr[i][j]);    
                }
                printf("\n");
        }
}
void *thread_routine(void *arg)
{
        int i,j,cancel_type;
        for(i=0;i<SIZE;i++)
                for(j=0;j<SIZE;j++)
                {
                        arr_a[i][j] = i;
                        arr_b[i][j] = j;
                }
        while(1)
        {
                pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,&cancel_type);
                 for(i=0;i<SIZE;i++)
                        for(j=0;j<SIZE;j++)
                        {
                                arr_c[i][j] = arr_a[i][j]*arr_b[i][j];
                        }
                pthread_setcanceltype(cancel_type,&cancel_type);
                for(i=0;i<SIZE;i++)
                        for(j=0;j<SIZE;j++)
                                arr_a[i][j] = arr_c[i][j];
        }
}
int main(void)
{
        pthread_t tid;                                                           
        void *result;
        pthread_create(&tid,NULL,thread_routine,NULL);
        sleep(1);
        printf("canceling!");
        pthread_cancel(tid);
        printf("joining");
        pthread_join(tid,&result);
        if(result==PTHREAD_CANCELED)
                printf("thread cancelled\n");
        else    
                printf("thread was not cancelled\n");
        printarr(arr_a);
        printarr(arr_b);
        printarr(arr_c);
}
View Code

 

5.清除
在编写代码时,应将其设计为可以推迟取消,在不适当的地方停用取消,在取消点使用清除处理器。

清除处理器可以理解为每个线程有一个活动的清除处理函数的栈,调用pthread_cleanup_push将清除函数加到栈中,调用pthread_cleanup_pop删除最近增加的处理函数。当所有活动的清除处理函数返回时,线程被终止。当pthread_cleanup_pop以非零值被调用时,即使线程没被取消,清除处理函数也要被执行。

代码示例如下:
当一个条件变量等待被取消时,使用一个清除处理函数来释放互斥量。

#include<stdio.h>                                                                
#include<pthread.h>
#define THREADS 5
typedef struct work_tag
{
        pthread_mutex_t mutex;
        pthread_cond_t cond;
        int counter;
        int busy;
}work_t;
work_t work = {PTHREAD_MUTEX_INITIALIZER,PTHREAD_COND_INITIALIZER,0,1};
void cleanup_handler(void *arg)
{
        work_t *work_p = (work_t*)arg;
        work_p->counter--;
        pthread_mutex_unlock(&work_p->mutex);
}
void *thread_routine(void *arg)
{
        pthread_cleanup_push(cleanup_handler,(void *)&work);
        pthread_mutex_lock(&work.mutex);
        work.counter++;
        while(work.busy)
        {
                pthread_cond_wait(&work.cond,&work.mutex);
        }
        pthread_cleanup_pop(1);
        return NULL;
}
int main(void)
{
        pthread_t tid[THREADS];
        void *result;
        int i;
        for(i=0;i<THREADS;i++)
        {
                pthread_create(&tid[i],NULL,thread_routine,NULL);
        }
        sleep(2);
        for(i=0;i<THREADS;i++)
        {
                pthread_cancel(tid[i]);
                pthread_join(tid[i],&result);
                if(result == PTHREAD_CANCELED)
                        printf("thread %d cancelled\n",i);
                else
                        printf("thread %d was not cancelled\n",i);
        }
        return 0;
}       
View Code

 

在一套“转包”功能的程序中,当分包线程在进行中时,承包线程被取消,这时不希望分包线程继续运行。可以在承包线程清除处理函数中取消每个分包线程,
如果原来是连接分包线程,它们将继续消费一些资源直到它们被连接或分离。这时应在承包线程清除处理函数中使用pthread_detach立即分离它。

代码示例如下:

#include<stdio.h>                                                                
#include<pthread.h>
#define THREADS 5
typedef struct send_tag
{
        pthread_t sid[THREADS];
}send_t;
void *send_routine(void *arg)
{
        int counter;
        for(counter=0;;counter++)
                if(counter%1000==0)
                        pthread_testcancel();
}
void cleanup(void *arg)
{
        send_t *send = (send_t*)arg;
        int i;
        for(i=0;i<THREADS;i++)
        {
                pthread_cancel(send->sid[i]);
                pthread_detach(send->sid[i]);
                printf("cleanup:cancelled %d\n",i);
        }
}
void *thread_routine(void *arg)
{
        send_t send;
        int i;
        void *result;
        for(i=0;i<THREADS;i++)
        {
                pthread_create(&send.sid[i],NULL,send_routine,NULL);
        }
        pthread_cleanup_push(cleanup,(void*)&send);
        for(i=0;i<THREADS;i++)
                pthread_join(send.sid[i],&result);
        pthread_cleanup_pop(0);
}
int main(void)
{
        pthread_t tid;
        void *result;
        pthread_create(&tid,NULL,thread_routine,NULL);
        sleep(5);
        pthread_cancel(tid);
        pthread_join(tid,&result);
        return 0;
}                                                                                
             
View Code

 

参考资料:《POSIX多线程程序设计》 pp.120-137

posted on 2016-04-17 23:56  迪米特  阅读(427)  评论(0编辑  收藏  举报

导航