【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.rhkb.cn/news/345794.html

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

相关文章

【深度学习】PuLID: Pure and Lightning ID Customization via Contrastive Alignment

论文&#xff1a;https://arxiv.org/abs/2404.16022 代码&#xff1a;https://github.com/ToTheBeginning/PuLID 文章目录 AbstractIntroductionRelated WorkMethods Abstract 我们提出了一种新颖的、无需调整的文本生成图像ID定制方法——Pure and Lightning ID customizatio…

机器学习笔记 - LoRA:大型语言模型的低秩适应

一、简述 1、模型微调 随着大型语言模型 (LLM) 的规模增加到数千亿,对这些模型进行微调成为一项挑战。传统上,要微调模型,我们需要更新所有模型参数。这也称为完全微调 (FFT) 。下图详细概述了此方法的工作原理。 完全微调FFT 的计算成本和资源需求很大,因为更新每…

Vue TypeScript 实战:掌握静态类型编程

title: Vue TypeScript 实战&#xff1a;掌握静态类型编程 date: 2024/6/10 updated: 2024/6/10 excerpt: 这篇文章介绍了如何在TypeScript环境下为Vue.js应用搭建项目结构&#xff0c;包括初始化配置、创建Vue组件、实现状态管理利用Vuex、配置路由以及性能优化的方法&#x…

拐点已至:企业如何借助AI重塑增长?

2024年的激进增长与AI数智化创新并行&#xff0c;传统策略的功效已经减弱。在这篇文章中&#xff0c;我们将展望并深度探索2024年的6大创新增长策略&#xff0c;包括AI驱动的实验&#xff0c;产品再造&#xff0c;超个性化&#xff0c;自动化运营&#xff0c;短视频和KOL营销等…

Kimichat使用案例010:快速识别出图片中的表格保存到Excel

文章目录 一、介绍二、图片信息三、输入内容四、输出内容五、markdown提示词六、markdown输出一、介绍 如果有一张图片格式的表格,想要快速复制到Excel表格中,那么一般要借助于OCR工具。之前试过不少在线OCR工具,识别效果差强人意。其实,kimichat就可以非常好的完成这个任务…

RPA-UiBot6.0数据整理机器人—杂乱数据秒变报表

前言 友友们是否常常因为杂乱的数据而烦恼?数据分类、排序、筛选这些繁琐的任务是否占据了友友们的大部分时间?这篇博客将为友友们带来一个新的解决方案,让我们共同学习如何运用RPA数据整理机器人,实现杂乱数据的快速整理,为你的工作减负增效! 在这里,友友们将了…

【微信小程序开发(从零到一)】——个人中心页面的实战项目(二)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

锂电池寿命预测 | Matlab基于SSA-SVR麻雀优化支持向量回归的锂离子电池剩余寿命预测

目录 预测效果基本介绍程序设计参考资料 预测效果 基本介绍 【锂电池剩余寿命RUL预测案例】 锂电池寿命预测 | Matlab基于SSA-SVR麻雀优化支持向量回归的锂离子电池剩余寿命预测&#xff08;完整源码和数据&#xff09; 1、提取NASA数据集的电池容量&#xff0c;以历史容量作…

搭建RocketMQ主从异步集群

搭建RocketMQ主从异步集群 1、RocketMQ集群模式 为了追求更好的性能&#xff0c;RocketMQ的最佳实践方式都是在集群模式下完成的。RocketMQ官方提供了三种集群搭建方式&#xff1a; 2主2从异步通信方式&#xff1a;使用异步方式进行主从之间的数据复制。吞吐量大&#xff0c;…

【日常记录】【JS】中文转拼音的库 pinyin-pro

文章目录 1、介绍2、pinyin-pro 基本使用3、参考链接 1、介绍 pinyin-pro 是一个专业的 JavaScript 中文转拼音的库&#xff0c;具备多音字识别准确、体积轻量、性能优异、功能丰富等特点。 常用的案例 搜索功能增强&#xff1a;在输入框输入汉字时&#xff0c;可以转化为拼音输…

YOLOv10 超详细解析 | 网络结构、训练策略、论文解读

网络结构 1. Backbone 2. Head 3. 说明 网络结构按 YOLOv10m 绘制&#xff0c;不同 scale 的模型在结构上略有不同&#xff0c;而不是像 YOLOv8 一样仅调整 depth 和 width。Head 有部分后续计算与 YOLOv8 完全相同&#xff0c;上图省略&#xff0c;具体请看此文。YOLOv10 整…

【Python教程】2-函数、逻辑运算与条件判断

在整理自己的笔记的时候发现了当年学习python时候整理的笔记&#xff0c;稍微整理一下&#xff0c;分享出来&#xff0c;方便记录和查看吧。个人觉得如果想简单了解一名语言或者技术&#xff0c;最简单的方式就是通过菜鸟教程去学习一下。今后会从python开始重新更新&#xff0…

Python基础——字符串

一、Python的字符串简介 Python中的字符串是一种计算机程序中常用的数据类型【可将字符串看作是一个由字母、数字、符号组成的序列容器】&#xff0c;字符串可以用来表示文本数据。 通常使用一对英文的单引号&#xff08;&#xff09;或者双引号&#xff08;"&#xff09;…

计算机网络ppt和课后题总结(下)

常用端口总结 计算机网络中&#xff0c;端口是TCP/IP协议的一部分&#xff0c;用于标识运行在同一台计算机上的不同服务。端口号是一个16位的数字&#xff0c;范围从0到65535。通常&#xff0c;0到1023的端口被称为“熟知端口”或“系统端口”&#xff0c;它们被保留给一些标准…

springboot高校运动会信息管理系统设计与实现-计算机毕业设计源码92968

摘 要 本论文介绍了一个高校运动会信息管理系统的设计和实现过程。首先是高校运动会的需求分析和可行性分析&#xff0c;通过比较运动会的各个工作流程&#xff0c;确定了系统的数据流程和数据库结构&#xff0c;然后介绍了高校运动会信息管理系统开发所使用的软件开发工具&…

Clo3D导出服装动画,使用Unity3D展示

1.前言 Clo3D是一款应用于时装行业的3D服装设计软件,其强大的布料模拟算法可在3D空间中实现设计、制版、试衣和走秀,大幅提升数字作品逼真度和制作效率。为了让服装动画效果展示在Unity3D上模拟效果&#xff0c;需要Clo3D模拟出逼着的衣服动画。总体流程为Clo3D - Mixamo -Blen…

【算法篇】求最长公共前缀JavaScript版本

题目描述 给你一个大小为 n 的字符串数组 strs &#xff0c;其中包含n个字符串 , 编写一个函数来查找字符串数组中的最长公共前缀&#xff0c;返回这个公共前缀。 数据范围&#xff1a; 数据范围:0<n<5000&#xff0c;0<len(strsi)< 5000 进阶:空间复杂度 O(1)&a…

金融数据中心能力建设指引

金融数据中心能力建设指引 金融数据中心能力建设指引旨在通过高标准的基础设施建设、完善的数据管理、强大的信息安全防护和业务连续性规划&#xff0c;确保数据中心具备高效、安全、可靠的运行能力&#xff0c;支持金融业务的稳定发展。该指引强调技术创新、标准化管理、人才…

【机器学习】Python与深度学习的完美结合——深度学习在医学影像诊断中的惊人表现

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 一、引言二、深度学习在医学影像诊断中的突破1. 技术原理2. 实际应用3. 性能表现 三、深度学习在医学影像诊断中的惊人表现1. 提高疾病诊断准确率2. 辅助制定治疗方案 四、深度学习对医疗行业的影响和推动作用 一、引言 随着…

Java加密体系结构参考指南-Java Cryptography Architecture

本文是从英文的官网摘了翻译的&#xff0c;用作自己的整理和记录。水平有限&#xff0c;欢迎指正。版本是&#xff1a;22 原文地址&#xff1a;https://docs.oracle.com/en/java/javase/22/security/java-cryptography-architecture-jca-reference-guide.html#GUID-815542FE-CF…