• UNIX环境编程学习笔记(28)——多线程编程(三):线程的取消


    lienhua34
    2014-11-24

    1 取消线程

    pthread 提供了pthread_cancel 函数用于请求取消同一进程中的其他线程。

    #include <pthread.h>

    int pthread_cancel(pthread_t tid);

    返回值:若成功则返回0,否则返回错误编码

    pthread_cancel 调用并不会立即终止目标线程,而只是向目标线程发出取消请求。调用线程不等待目标线程终止,在默认情况下,目标线程在取消请求发出以后还是继续运行的,直到目标线程到达某个取消点。取消点是线程检查是否被取消并按照请求进行动作的一个位置。

    下面我们来看个线程取消的例子。主线程创建一个新线程,新线程循环睡眠 5 秒钟然后返回 2. 而主线程在创建新线程之后睡眠 2 秒钟便调用pthread_cancel 来请求取消新线程。最后获取新线程的退出状态。

    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <pthread.h>
    
    void *
    my_thread(void *arg)
    {
        int i=0;
    
        printf("[new thread]: I will sleep 5 seconds.
    ");
        while (i < 5) {
          sleep(1);
          i = i + 1;
          printf("[new thread]: %d
    ", i);
        }
        printf("[new thread]: exit now.
    ");
        return ((void *)0);
    }
    
    int
    main(void)
    {
      int err;
      pthread_t tid;
      void *tret;
    
      err = pthread_create(&tid, NULL, my_thread, NULL);
      if ( err != 0) {
        printf("can't create thread: %s
    ", strerror(err));
        exit(-1);
      }
    
      sleep(2);
      printf("[main thread]: cancel new thread.
    ");
      err = pthread_cancel(tid);
      if (err != 0) {
        printf("can't cancel thread: %s
    ", strerror(err));
        exit(-1);
      }
    
      err = pthread_join(tid, &tret);
      if (err != 0) {
        printf("can't join with new thread: %s
    ", strerror(err));
        exit(-1);
      } else {
        if (PTHREAD_CANCELED == tret) {
          printf("new thread has been canceled.
    ");
        } else {
          printf("new thread exit code: %d
    ", (int)tret);
        }
      }
      
      exit(0);
    }

    编译该程序,生成并执行文件pthread_cancel_demo,

    lienhua34:demo$ gcc -o pthread_cancel_demo -pthread pthread_cancel_demo.c
    lienhua34:demo$ ./pthread_cancel_demo
    [new thread]: I will sleep 5 seconds.
    [new thread]: 1
    [main thread]: cancel new thread.
    new thread has been canceled.

    如果某个线程响应了取消请求相当于调用了参数为PTHREAD_CANCELED的pthread_exit 函数。

    2 线程取消属性

    前面学习了可以通过pthread_attr_t 结构来控制线程的属性。但是有两个与线程取消的属性没有包含在pthread_attr_t 结构中,它们是可取消状态和可取消类型。

    2.1 可取消状态

    可取消状态属性是个使能属性,控制了线程是否要响应其他线程的取消请求。该属性可以是PTHREAD_CANCEL_ENABLE,或者是PTHREAD_CANCEL_DISABLE。线程的可取消属性默认为前者。如果设置为后者,则线程将不会响应取消请求,不过取消请求对于该线程来说处于未决状态,当可取消状态再次变为PTHREAD_CANCEL_ENABLE 时,线程将在下个取消点上对所有未决的取消请求进行处理。

    线程可以通过调用pthread_setcancelstate 函数来修改其可取消状态。

    #include <pthread.h>

    int pthread_setcancelstate(int state, int *oldstate);

    返回值:若成功则返回0,否则返回错误编号

    该函数将线程的当前可取消状态设置为 state,并通过 oldstate 返回原来的可取消状态。

    下面我们来看那个例子,我们在上面的pthread_cancel_demo.c 程序的新线程入口函数my_thread 的开始调用pthread_setcancelstate 函数将新线程的可取消状态设置为PTHREAD_CANCEL_DISABLE。

    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <pthread.h>
    
    void *
    my_thread(void *arg)
    {
        int i=0;
        int err;
        err = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
        if (err != 0) {
          printf("[new thread]: can't set cancel state: %s
    ", strerror(err));
        }
        printf("[new thread: disable cancel state.
    ");
        
        printf("[new thread]: I will sleep 5 seconds.
    ");
        while (i < 5) {
          sleep(1);
          i = i + 1;
          printf("[new thread]: %d
    ", i);
        }
        printf("[new thread]: exit now.
    ");
        return ((void *)0);
    }
    
    int
    main(void)
    {
      int err;
      pthread_t tid;
      void *tret;
    
      err = pthread_create(&tid, NULL, my_thread, NULL);
      if ( err != 0) {
        printf("can't create thread: %s
    ", strerror(err));
        exit(-1);
      }
    
      sleep(2);
      printf("[main thread]: cancel new thread.
    ");
      err = pthread_cancel(tid);
      if (err != 0) {
        printf("can't cancel thread: %s
    ", strerror(err));
        exit(-1);
      }
    
      err = pthread_join(tid, &tret);
      if (err != 0) {
        printf("can't join with new thread: %s
    ", strerror(err));
        exit(-1);
      } else {
        if (PTHREAD_CANCELED == tret) {
          printf("new thread has been canceled.
    ");
        } else {
          printf("new thread exit code: %d
    ", (int)tret);
        }
      }
      
      exit(0);
    }

    编译该程序,生成并执行pthread_cancel_demo 文件,

    lienhua34:demo$ gcc -o pthread_cancel_demo -pthread pthread_cancel_demo.c
    lienhua34:demo$ ./pthread_cancel_demo
    [new thread: disable cancel state.
    [new thread]: I will sleep 5 seconds.
    [new thread]: 1
    [main thread]: cancel new thread.
    [new thread]: 2
    [new thread]: 3
    [new thread]: 4
    [new thread]: 5
    [new thread]: exit now.
    new thread exit code: 0

    从上面的运行结果与前一节的运行结果对比,我们可以看出将新线程的可取消状态设置为PTHREAD_CANCEL_DISABLE 后,新线程没有响应主线程的取消请求。

    2.2 可取消类型

    上面所说的线程在到达某个取消点的时候会去检查一下是否被取消。这种取消类型也称为延迟取消。另外,还有一种取消类型是异步取消。当线程的取消类型为异步取消时,线程可以在任意时间被取消。

    线程可以通过调用pthread_setcanceltype 来修改线程的取消类型。

    #include <pthread.h>

    int pthread_setcanceltype(int type, int *oldtype);

    返回值:若成功则返回0,否则返回错误编号

    其中type参数可以是PTHREAD_CANCEL_DEFERRED(延迟取消), 或者PTHREAD_CANCEL_ASYNCHRONOUS(异步取消)。该函数将线程的当前可取消类型设置为 type,然后将原来的可取消类型通过 oldtype 参数返回。

    (done)

  • 相关阅读:
    Git之常用的命令操作
    Linux之创建777权限的文件
    Mysql union
    读取MySQL数据表字段信息
    Linux下mysql启动失败
    TP5之使用layui分页样式
    使用Bootstrap实现表格列的显示与隐藏
    MySQL之避免插入重复数据
    Linux命令之清空当前文件
    opensns入门
  • 原文地址:https://www.cnblogs.com/lienhua34/p/4119977.html
Copyright © 2020-2023  润新知