当前位置: 首页 > news >正文

【PTHREAD】线程退出与取消

1 线程退出

线程正常退出的几种方式:

  • 在线程工作函数中调用pthread_exit,此时可使用pthread_join接收pthread_exit的参数值

  • 线程工作函数运行结束

  • 同一进程中的任意一个子线程调用exit,或者主线程结束

  • 线程可以被从另一个线程中取消pthread_cancel

1.1 API

void pthread_exit(void *retval);
  • 如果为链接态线程,参数retval指示的返回值,可用pthread_join进行接收

1.2 案例:显式退出链接态线程

  • 源码

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <pthread.h>
    
    void *start_routine(void *ptr)
    {
        printf("子线程(%lu)开始运行...\n", pthread_self());
    
        int num = 0;
        while (1)
        {
            printf("子线程(%lu)正在执行,%d...\n", pthread_self(), ++num);
            sleep(1);
            if (num > 3)
                pthread_exit((void **)"8888");
        }
    
        printf("子线程(%lu)即将退出...\n", pthread_self());
        return (void *)"9999";
    }
    
    int main(int argc, char const *argv[])
    {
        printf("主线程(%lu)开始运行...\n", pthread_self());
    
        pthread_t thread_id;
        pthread_create(&thread_id, NULL, start_routine, NULL);
    
        void *retval = NULL;
        pthread_join(thread_id, &retval);
        printf("子线程的返回值为:%s\n", (const char *)retval);
    
        printf("主线程(%lu)即将退出...\n", pthread_self());
        exit(EXIT_SUCCESS);
    }
    
  • 输出

    主线程(140657300412224)开始运行…
    子线程(140657300408064)开始运行…
    子线程(140657300408064)正在执行,1…
    子线程(140657300408064)正在执行,2…
    子线程(140657300408064)正在执行,3…
    子线程(140657300408064)正在执行,4…
    子线程的返回值为:8888
    主线程(140657300412224)即将退出…

2 线程取消

2.1 API

int pthread_cancel(pthread_t thread);

发送一个取消请求。目标线程是否响应与什么时候响应依赖于可取消状态可取消类型属性。

2.2 可取消状态

int pthread_setcancelstate(int state, int *oldstate);

可取消状态可通过函数pthread_setcancelstate函数进行设置。默认为启用。

  • 如果线程禁用(PTHREAD_CANCEL_DISABLE)了可取消状态属性,则取消请求将保留到可取消状态被启用
  • 如果线程启用(PTHREAD_CANCEL_ENABLE)了可取消状态属性,则可取消类型决定取消行为什么时候发生

2.3 可取消类型

int pthread_setcanceltype(int type, int *oldtype);

可以取消类型可通过函数pthread_setcanceltype函数进行设置。可能值为异步延迟

  • 异步(PTHREAD_CANCEL_ASYNCHRONOUS

    异步的可取消类型意味着可以在任意时刻取消(通常是立即取消,但系统不保证)。

  • 延迟(PTHREAD_CANCEL_DEFERRED

    异步的可取消类型意味着取消被延迟直到下次调用取消点函数

    取消点函数列表可通过man 7 pthreads进行查询

2.3 取消过程

void pthread_cleanup_push(void (*routine)(void *), void *arg);
void pthread_cleanup_pop(int execute);

当一个取消请求被实施,将按下述步骤进行实施:

  • 取消清理函数入栈与调用(pthread_cleanup_push
  • 线程私有数据的析构函数以不确定顺序的方式被调用
  • 终结线程

2.4 案例:取消线程执行

  • 源码

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <pthread.h>
    
    void *start_routine_01(void *ptr)
    {
        printf("子线程(%lu)开始运行...\n", pthread_self());
    
        int num = 0;
        while (1)
        {
            printf("子线程(%lu)正在执行,%d...\n", pthread_self(), ++num);
            sleep(1);
        }
    
        printf("子线程(%lu)即将退出...\n", pthread_self());
        return (void *)"8888";
    }
    
    void *start_routine_02(void *ptr)
    {
        printf("子线程(%lu)开始运行...\n", pthread_self());
    
        sleep(3);
        pthread_cancel(*((pthread_t*)ptr));
        printf("子线程(%lu)取消信号已发出\n", pthread_self());
    
        printf("子线程(%lu)即将退出...\n", pthread_self());
        return (void *)"9999";
    }
    
    int main(int argc, char const *argv[])
    {
        printf("主线程(%lu)开始运行...\n", pthread_self());
    
        pthread_t thread_id_01;
        pthread_create(&thread_id_01, NULL, start_routine_01, NULL);
    
        pthread_t thread_id_02;
        pthread_create(&thread_id_02, NULL, start_routine_02, &thread_id_01);
    
        pthread_join(thread_id_01, NULL);
        pthread_join(thread_id_02, NULL);
    
        printf("主线程(%lu)即将退出...\n", pthread_self());
        exit(EXIT_SUCCESS);
    }
    
  • 输出

    主线程(140162664855360)开始运行…
    子线程(140162664851200)开始运行…
    子线程(140162664851200)正在执行,1…
    子线程(140162656458496)开始运行…
    子线程(140162664851200)正在执行,2…
    子线程(140162664851200)正在执行,3…
    子线程(140162664851200)正在执行,4…
    子线程(140162656458496)取消信号已发出
    子线程(140162656458496)即将退出…
    主线程(140162664855360)即将退出…

相关文章:

  • 组件命名报错 “Component name “XXX“ should always be multi-word”的解决方法
  • 离职前一定要删除这几个文件,不然你的微信聊天记录全被别人看了
  • Vue(模板语法1)
  • 银行利率bp是什么意思,bp是什么意思贷款利率
  • 暗月项目四
  • 目标检测——关键点检测学习记录(三):人体骨骼点检测——自底向上
  • 隐私计算+区块链原生融合之后平台开放、提升性能,蚂蚁链隐私协作平台FAIR重磅架构升级
  • Loki 收集Nginx日志以 grafana 可视化展示
  • 异常与错误处理高级用法
  • Java学习----Map接口
  • 设计模式-概述. 类图.软件设计原则详细讲解
  • 条件渲染(v-if、v-show)、列表渲染(v-for)、列表中key的原理和作用、列表过滤(filter)、列表排序(sort)
  • openarena
  • 【蓝桥杯省赛真题37】Scratch三国演义字数统计 少儿编程scratch编程蓝桥杯省赛真题讲解
  • Linux内核设计与实现 第三章 进程管理
  • [译] React v16.8: 含有Hooks的版本
  • 2017前端实习生面试总结
  • Apache的80端口被占用以及访问时报错403
  • echarts的各种常用效果展示
  • ES6, React, Redux, Webpack写的一个爬 GitHub 的网页
  • Javascript 原型链
  • JS+CSS实现数字滚动
  • Mybatis初体验
  • NSTimer学习笔记
  • Redux系列x:源码分析
  • v-if和v-for连用出现的问题
  • vue-cli3搭建项目
  • 第三十一到第三十三天:我是精明的小卖家(一)
  • 计算机在识别图像时“看到”了什么?
  • 区块链共识机制优缺点对比都是什么
  • 腾讯视频格式如何转换成mp4 将下载的qlv文件转换成mp4的方法
  • 小李飞刀:SQL题目刷起来!
  • 异步
  • nb
  • ​2020 年大前端技术趋势解读
  • ​决定德拉瓦州地区版图的关键历史事件
  • !! 2.对十份论文和报告中的关于OpenCV和Android NDK开发的总结
  • #include
  • #Linux(Source Insight安装及工程建立)
  • (day 12)JavaScript学习笔记(数组3)
  • (补)B+树一些思想
  • (动态规划)5. 最长回文子串 java解决
  • (多级缓存)多级缓存
  • (分享)一个图片添加水印的小demo的页面,可自定义样式
  • (附源码)springboot家庭装修管理系统 毕业设计 613205
  • (学习日记)2024.02.29:UCOSIII第二节
  • (一)使用Mybatis实现在student数据库中插入一个学生信息
  • (原创)攻击方式学习之(4) - 拒绝服务(DOS/DDOS/DRDOS)
  • (原創) 如何安裝Linux版本的Quartus II? (SOC) (Quartus II) (Linux) (RedHat) (VirtualBox)
  • (转)setTimeout 和 setInterval 的区别
  • ***linux下安装xampp,XAMPP目录结构(阿里云安装xampp)
  • .NET Core 实现 Redis 批量查询指定格式的Key
  • .NET 事件模型教程(二)
  • .net6Api后台+uniapp导出Excel
  • /dev/sda2 is mounted; will not make a filesystem here!