zoukankan      html  css  js  c++  java
  • 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
    ");
                            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
    ");
            pthread_cancel(tid);
            printf("call joining
    ");
            pthread_join(tid,&result);
            if(result==PTHREAD_CANCELED)
            {
                printf("Thread cancelled at %d
    ",counter);
            }
            else{
                    printf("Thread was not canceled
    ");
            }
            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
    ");
                            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
    ");
            pthread_cancel(tid);
            printf("call joining
    ");
            pthread_join(tid,&result);
            if(result==PTHREAD_CANCELED)
            {
                    printf("Thread cancelled at %d
    ",counter);
            }
            else{
                    printf("Thread was not canceled
    ");
            }
            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("
    ");
            }
    }
    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
    ");
            else    
                    printf("thread was not cancelled
    ");
            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
    ",i);
                    else
                            printf("thread %d was not cancelled
    ",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
    ",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

  • 相关阅读:
    轻松实现WCF服务的构造函数依赖注入
    终于找到在Visual Studio 2010中进行“项目重命名”的有效工具
    让Entity Framework不再私闯sys.databases
    AutoMapper使用笔记
    遭遇IE8下的JavaScript兼容问题
    WCF异步调用中客户端关闭带来的性能问题
    Chrome “False Start” 引起的 Error 7 (net::ERR_TIMED_OUT): The operation timed out
    实战ASP.NET访问共享文件夹(含详细操作步骤)
    Entity Framework 理清关系 基于外键关联的单向一对一关系
    在Firefox中通过JavaScript复制到剪贴板(Copy to Clipboard)
  • 原文地址:https://www.cnblogs.com/shijingjing07/p/5402881.html
Copyright © 2011-2022 走看看