【Linux多线程】线程的终止、等待和分离

文章目录

  • 线程终止
    • 正常退出
      • return 退出
      • pthread_exit函数终止线程
    • pthread_cancel强制终止线程
    • 进程终止
  • 线程等待
    • 为什么需要等待线程?
    • pthread_join函数
  • 分离线程
    • pthread_detach函数

线程终止

下面给出终止线程的三种方式:

  1. 正常退出
    • 线程执行完它的函数之后return自动结束
    • 线程显示调用pthread_exit函数退出
  2. 强制终止
    • 一个线程可以被另一个线程通过pthread_cancel函数强制退出
  3. 进程终止
    • 一个进程终止,那么该进程的所有线程都会终止

下面将分别模拟这三种终止线程的方式:

正常退出

return 退出

给出下面代码模拟线程return终止

#include <pthread.h>
#include <iostream>
#include <unistd.h>
#include <string.h>
using namespace std;void *rout(void *arg)
{int cnt = 3;while (cnt--){cout << "thread id :  " << pthread_self() << "  i am thread num:  " << *(int *)arg << endl;sleep(1);}cout << "phread end....." << endl;sleep(1);return NULL;
}int main()
{pthread_t tid;int num = 10;int res = pthread_create(&tid, NULL, rout, (void *)(&num));pthread_join(tid, NULL); // 等待线程结束sleep(20);cout << "wait success! main thread end!" << endl;return 0;
}

在这里插入图片描述
观察上面代码运行情况,发现当线程return之后确实被终止了(上图多出来一个线程是库里面的管理线程,不必理会)。

pthread_exit函数终止线程

pthread-exit函数用于终止当前线程
函数原型:

void pthread_exit(void *value_ptr);
  • value_ptr是一个任意类型的指针,表示线程的退出状态。其它线程可以通过pthread_join函数获取这个状态

给出下面代码观察线程终止

#include <pthread.h>
#include <iostream>
#include <unistd.h>
#include <string.h>
using namespace std;void *rout(void *arg)
{int cnt = 3;int *status = new int(20);while (true){cout << "thread id :  " << pthread_self() << "  i am thread num:  " << *(int *)arg << endl;sleep(1);if (cnt == 0){cout << "phread exit....." << endl;pthread_exit((void *)(status));}cnt--;}// cout << "phread end....." << endl;// sleep(1);return NULL;
}int main()
{pthread_t tid;int num = 10;int res = pthread_create(&tid, NULL, rout, (void *)(&num));void *status = NULL;pthread_join(tid, &status); // 等待线程结束sleep(5);cout << "wait success! main thread end! status: " << *(int *)(status) << endl;return 0;
}

在这里插入图片描述
需要注意,pthread_exit或者return返回的指针指向的内存单元应该是全局的,因为线程终止之后其函数栈帧会销毁,之后才会返回一个void*指针。

pthread_cancel强制终止线程

功能:取消一个执行中的线程
函数原型:

int pthread_cancel(pthread_t thread);
  • thread表示要删除的线程id(用户级)
  • 成功返回0,否则返回错误码

给出代码样例,观察pthread_cancel函数的使用

#include <pthread.h>
#include <iostream>
#include <unistd.h>
#include <string.h>
using namespace std;void *rout(void *arg)
{int cnt = 3;int *status = new int(20);while (true){cout << "thread id :  " << pthread_self() << "  i am thread num:  " << *(int *)arg << endl;sleep(1);// if (cnt == 0)// {//     cout << "phread exit....." << endl;//     pthread_exit((void *)(status));// }// cnt--;}// cout << "phread end....." << endl;// sleep(1);return NULL;
}int main()
{pthread_t tid;int num = 10;int res = pthread_create(&tid, NULL, rout, (void *)(&num));void *status = NULL;sleep(5);pthread_cancel(tid); // 强制终止tidcout << "thread is end" << endl;pthread_join(tid, &status); // 等待线程结束sleep(3);cout << "wait success! main thread end! status: " << *(int *)(status) << endl;return 0;
}

在这里插入图片描述
在主线程中调用pthread_cancel函数强制终止了执行rout函数的线程。

进程终止

进程终止,该进程的所有线程都终止。比如在函数中调用exit终止进程。

void *rout(void *arg)
{int cnt = 3;int *status = new int(20);while (true){cout << "thread id :  " << pthread_self() << "  i am thread num:  " << *(int *)arg << endl;sleep(1);if (cnt == 0){cout << "phread exit....." << endl;exit(0);}cnt--;}return NULL;
}

一旦调用exit或者异常而终止进程,该进程的所有线程都玩完。道理很简单,这里就不做演示了。

线程等待

为什么需要等待线程?

其实已经退出的线程并没有完全“结束”,其栈帧并没有随着线程终止马上就释放,仍然在进程的地址空间里。并且,如果不对这些已经终止但是还没有被释放空间的线程做处理,往后继续创建新线程都不会复用前面退出线程的地址空间,这就造成了资源的浪费。这种情况其实非常像我们之前谈过的僵尸进程问题。

等待线程终止就是提醒内核可以释放这个线程的资源了。等待线程终止其实也是为了确保线程完成任务。有时主线程或者其他线程需要等待某一个线程任务完成之后才能继续执行。等待一个线程结束,其实就是让终止的线程退出时“通知”一下其它线程,可以不关心退出线程的返回结果。此外,等待线程终止在某些情况下能保证数据的完整性,比如线程一处理上半段数据,线程二处理下半段数据,如果其中任何一个线程没有终止,那总数据就会不完整。

为了实现线程终止时的等待问题,linux提供了pthread_join函数。

pthread_join函数

作用:阻塞调用该函数线程,直到目标线程终止。
函数原型:

#include<pthread.h>
int pthread_join(pthread_t thread,void** retval);

在这里插入图片描述
其中:

  • thread表示所等待线程的线程标识符
  • retval是一个输出型参数,指向等待线程的退出信息
  • 成功返回0,否则返回错误码

值得注意的是,线程终止方式的不同,其通过pthread_join得到的退出信息也就不同。比如:

  1. 目标线程通过return 终止(或者是pthread_exit),retval所指向的单元里存放的就是目标线程执行函数的返回值。
    观察下面代码,分析线程return终止时,pthread_join得到的返回值
#include <pthread.h>
#include <iostream>
#include <unistd.h>
#include <string.h>
using namespace std;void *rout(void *arg)
{int cnt = 3;int *status = new int(20);int num = 20;while (cnt--){cout << "thread id :  " << pthread_self() << "  i am thread num:  " << *(int *)arg << endl;sleep(1);}// pthread_exit((void *)status);return (void *)status;
}int main()
{pthread_t tid;int num = 10;int res = pthread_create(&tid, NULL, rout, (void *)(&num));void *status = NULL;cout << "main pthread wait...." << endl;pthread_join(tid, &status); // 等待线程结束sleep(3);cout << "wait success! main thread end! status: " << *(int *)(status) << endl;return 0;
}

在这里插入图片描述

  1. 如果线程是被别的线程通过调用pthread_cancel函数强制终止掉,retval所指向单元存放的就是常数PTHREAD_ CANCELED

给出代码样例观察结果:

#include <pthread.h>
#include <iostream>
#include <unistd.h>
#include <string.h>
using namespace std;void *rout(void *arg)
{int cnt = 3;int *status = new int(20);int num = 20;while (cnt--){cout << "thread id :  " << pthread_self() << "  i am thread num:  " << *(int *)arg << endl;sleep(1);}pthread_exit((void *)status);// return (void *)status;
}int main()
{pthread_t tid;int num = 10;int res = pthread_create(&tid, NULL, rout, (void *)(&num));void *status = NULL;sleep(2);pthread_cancel(tid);pthread_join(tid, &status); // 等待线程结束if (status == PTHREAD_CANCELED){cout << "pthread is cancel" << endl;}return 0;
}

在这里插入图片描述
retval所指向单元存放的就是常数PTHREAD_ CANCELED得证。

  1. 如果不关心某一个线程的退出信息,可以return NULL。比如:
void* thread_function(void* arg) {// 线程的工作printf("Thread is running\n");return NULL;
}

总结:

分离线程

分离线程实际上是线程的一种状态,这种状态表示该进程不需要被等待,且线程退出后会自动释放资源。对于主线程来说,有些线程独立执行任务,其它线程没有必要再调用pthread_join阻塞等待。这样提升了整体的效率。一般来说,创建的新线程默认都是joinable的,也就是需要被等待的,我们可以通过pthread_detach函数来改变这一性质。

pthread_detach函数

功能:分离一个目标线程,使该线程终止后自动释放资源,不需要被等待
函数原型:

#include<pthread.h>
int pthread_detach(pthread_t thread);
  • thread表示分离的目标线程,也可以是调用该函数的线程本身
  • 成功放回0,否则-1

给出代码样例,观察pthread_detach函数的使用

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
using namespace std;void *thread_run(void *arg)
{pthread_detach(pthread_self());printf("%s\n", (char *)arg);return NULL;
}int main(void)
{pthread_t tid;if (pthread_create(&tid, NULL, thread_run, (void *)"thread1 run...") != 0){printf("create thread error\n");return 1;}int ret = 0;sleep(1); // 很重要,要让线程先分离,再等待if (pthread_join(tid, NULL) == 0){printf("pthread wait success\n");ret = 0;}else{printf("pthread wait failed\n");ret = 1;}return ret;
}

在这里插入图片描述
分析上述代码,因为执行thread_run函数的线程设置成了分离状态,函数结束之后自动释放资源。此时再去用pthread_join函数去等待这个线程就会得到返回值0。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/23241.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【学习心得】算法刷题心得分享

一、为什么要刷题&#xff1f; 提升编程能力&#xff0c;强化对数据结构的理解&#xff0c;熟练掌握常用的算法等为竞赛、考试做准备找实习、找工作需要&#xff08;上机考试面试手撕代码&#xff09;提升自信心&#xff0c;放松一下 二、刷题前应该有哪些知识储备&#xff1f;…

JMH307【亲测】 怀旧端游【WD】1.73单机版带GM后台视频安装教程虚拟机端

资源介绍&#xff1a; 是否需要虚拟机&#xff1a;是 文件大小&#xff1a;压缩包约8G 支持系统&#xff1a;win7、win10、win11 硬件需求&#xff1a;运行内8G 4核及以上CPU 资源截图&#xff1a; 下载地址

BERT+PET方式数据处理

基于BERTPET方式数据预处理介绍 BERTPET方式数据预处理&#x1f43e; 本项目中对数据部分的预处理步骤如下: 查看项目数据集编写Config类项目文件配置代码编写数据处理相关代码 1 查看项目数据集&#x1f43e; 数据存放位置&#xff1a;/Users/***/PycharmProjects/llm/prom…

uniapp内置的button组件的问题

问题描述 由于想要使用uniapp内置button组件的开放能力&#xff0c;所以就直接使用了button&#xff0c;但是他本身带着边框&#xff0c;而且使用 border&#xff1a;none&#xff1b;是没有效果的。 问题图片 解决方案 button::after {border: none;} 正确样式 此时的分享…

HarmonyOS(31) @Prop标签使用指南

Prop Prop简介State和Prop的同步场景使用示例参考资料 Prop简介 子组件中Prop装饰的变量可以和父组件建立单向的同步关系。子组件Prop装饰的变量是可变的&#xff0c;但是变化不会同步回其父组件。Prop变量允许子组件修改&#xff0c;但修改后的变化不会同步回父组件。当父组件…

python书上的动物是啥

Python的创始人为Guido van Rossum。1989年圣诞节期间&#xff0c;在阿姆斯特丹&#xff0c;Guido为了打发圣诞节的无趣&#xff0c;决心开发一个新的脚本解释程序&#xff0c;做为ABC语言的一种继承。之所以选中Python作为程序的名字&#xff0c;是因为他是一个叫Monty Python…

【核心动画-转场动画-CATransition Objective-C语言】

一、转场动画,CATransition, 1.接下来,我们来说这个转场动画啊,效果呢,会做这么一个小例子, 感觉有一个3D的一个样式一样, 转场动画呢,就是说,你在同一个View,比如说,imageView,去切换图片的时候,你可以去用这个,转场动画, 实际上,包括,控制器之间的切换,也…

新手上路:Linux虚拟机创建与Hadoop集群配置指南①(未完)

一、基础阶段 Linux操作系统: 创建虚拟机 1.创建虚拟机 打开VM,点击文件,新建虚拟机,点击自定义,下一步 下一步 这里可以选择安装程序光盘映像文件,我选择稍后安装 选择linux系统 位置不选C盘,创建一个新的文件夹VM来放置虚拟机,将虚拟机名字改为master方便后续识别…

期望24K,商汤科技golang开发 社招一二三 + hr 面

商汤科技对数据库和中间件相关的东西问的比其他的大厂要少很多&#xff0c;可能他们更多是和算法相关&#xff0c;没有什么高并发的场景。总体感觉对技术的要求不是特别高。当时问了他们主管&#xff0c;我面试的部门的工作是主要去实现他们算法部门研究的算法&#xff0c;感觉…

[图解]企业应用架构模式2024新译本讲解09-领域模型2

1 00:00:01,750 --> 00:00:03,030 代码还是一样的 2 00:00:03,040 --> 00:00:12,640 我们还是从前面人家做的复刻案例来看 3 00:00:14,170 --> 00:00:15,200 这个是它的类图 4 00:00:15,640 --> 00:00:20,650 我们同样用UModel逆转&#xff0c;这个太小了&#…

windows RNDIS开发-概念

远程 NDIS (RNDIS) 是一种独立于总线的类&#xff0c;适用于动态 即插即用 (PnP) 总线&#xff08;例如 USB、1394、蓝牙和 InfiniBand&#xff09;上的以太网 (802.3) 网络设备。 远程 NDIS 通过抽象控制和数据通道在主计算机与远程 NDIS 设备之间定义与总线无关的消息协议。 …

【微信小程序】页面导航

声明式导航 导航到 tabbar 页 tabBar页面指的是被配置为tabBar的页面。 在使用<navigator>组件跳转到指定的tabBar页面时&#xff0c;需要指定url属性和open-type属性&#xff0c;其中&#xff1a; url 表示要跳转的页面的地址&#xff0c;必须以/开头open-type表示跳…

spring boot3登录开发-2(3邮件验证码接口实现)

⛰️个人主页: 蒾酒 &#x1f525;系列专栏&#xff1a;《spring boot实战》 目录 写在前面 上文衔接 接口设计与实现 1.接口分析 2.实现思路 3.代码实现 1.定义验证码短信HTML模板枚举类 2.定义验证码业务接口 3. 验证码业务接口实现 4.控制层代码 4.测试 写…

场外个股期权标的有哪些?

今天带你了解场外个股期权标的有哪些&#xff1f;场外个股期权是一种金融衍生品&#xff0c;它不在交易所内进行交割&#xff0c;而是在交易所以外的场所进行交易的股票期权合约。 场外个股期权标的有哪些&#xff1f; 场外个股期权的标的通常包括A股市场上的融资融券标的&…

ARM服务器在云手机中可以提供哪些支持

ARM服务器作为云手机的底层支撑&#xff0c;在很多社媒APP或者电商APP平台都有着很多看不见的功劳&#xff0c;可以说ARM扮演着至关重要的底层支持角色&#xff1b; 首先&#xff0c;ARM 服务器为云手机提供了强大的计算能力基础。云手机需要处理大量的数据和复杂的运算&#x…

微服务第一轮

课程文档 目录 一、业务流程 1、登录 Controller中的接口&#xff1a; Service中的实现impl&#xff1a; Service中的实现impl所继承的接口IService&#xff08;各种方法&#xff09;&#xff1a; VO&#xff1a; DTO&#xff1a; 2、搜索商品 ​Controller中的接口&a…

【亚马逊云科技 CSDN 联合巨献】 「对话AI 构建者:从基础到应用的 LLM 全景培训」 限时免费!

&#x1f680;&#x1f31f;【亚马逊云科技 & CSDN 联合巨献】 &#x1f4da;「对话AI 构建者&#xff1a;从基础到应用的 LLM 全景培训」&#x1f525; 限时免费&#xff01; &#x1f4c6; 抓紧时间&#xff01;6月7日前注册&#xff0c;原价 399&#xff0c;现在仅需 0…

C基础与SDK调试方法

REVIEW 上次学习了一下软件使用流程zynq PS点灯-CSDN博客 本次学习一下C编程基础与调试方法 1. 硬件编程原理 小梅哥视频链接&#xff1a; 07_Xilinx嵌入式裸机硬件编程原理_哔哩哔哩_bilibili 对应的课程笔记&#xff1a;【zynq课程笔记】【裸机】【第7课 】【硬件编程原理…

C++ STL - 容器

C STL&#xff08;标准模板库&#xff09;中的容器是一组通用的、可复用的数据结构&#xff0c;用于存储和管理不同类型的数据。 目录 零. 简介&#xff1a; 一 . vector&#xff08;动态数组&#xff09; 二. list&#xff08;双向链表&#xff09; 三. deque&#xff08…

yolov8摔倒检测(包含数据集+训练好的模型)

基于先进的YOLOv8模型&#xff0c;实现了一套高效可靠的人体摔倒检测系统。YOLOv8作为YOLO系列的最新成员&#xff0c;以其卓越的检测速度和准确性&#xff0c;在计算机视觉领域尤其是目标检测任务中表现出色。本系统不仅能够实时处理视频流或监控画面&#xff0c;还能对静态图…