Linux: 线程控制

目录

一 前言

二 线程控制

1. POSIX线程库(原生线程库)

2. 创建线程

2.1 pthread_create

 2.2pthread_self()获取线程id

 3.线程终止

3.1.return 方式

3.2 pthread_exit 

 4 线程等待

三 理解线程tid 


一 前言

   在上一篇文章中我们已经学习了线程的概念,线程的创建,并且已经从根本上了解了线程和进程的相同点及不同点。在学习进程时,我们学习了进程的相关概念,进程控制接口,而线程作为更轻量级的进程,其自然也有着控制接口。 


二 线程控制

1. POSIX线程库(原生线程库)

  • 与线程有关的函数构成了一个完整的系列,绝大多数函数的名字都是以“pthread_”打头的
  • 要使用这些函数库,要通过引入头文 件 <pthread.h>
  • 链接这些线程函数库时要使用编译器命令的“-lpthread”选项

2. 创建线程

2.1 pthread_create

功能:创建一个新的线程

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void * (*start_routine)(void*), void *arg);

  1. 参数 thread:返回线程ID
  2. attr:设置线程的属性,attr为NULL表示使用默认属性
  3. start_routine:是个函数地址,线程启动后要执行的函数
  4. arg:传给线程启动函数的参数
  5. 返回值:成功返回0;失败返回错误

上一章节我们是创建了一个线程,接下来我们创建多个线程

#include <iostream>
#include <string>
#include <pthread.h>
#include <unistd.h>
#include <vector>
#include <cstdio>using namespace std;void* start_routine(void* args )
{string name=static_cast<const char*>(args);//安全类型转换while(true){cout<<"new thread create success, name: "<<name<<endl;sleep(1);}
}int main()
{//1.创建一批线程vector<pthread_t> tids;#define NUM 10for(int i=0;i<NUM;i++){pthread_t tid;char namebuffer[64];snprintf(namebuffer,sizeof namebuffer,"%s: %d","thread",i);//为每个线程设置编号// pthread_t id;//一旦创建成功,就执行上面的执行流pthread_create(&tid,nullptr,start_routine,(void*)namebuffer);}// //2.主执行流while(true){   cout<<"new thread create success, name: main thread"<<endl;sleep(1);}

 测试结果

🍉:从测试结果我们观察到和我们预想的结果不一样,接下来我们用下图解释

接下来我们对代码进行一定修改 

 void* start_routine(void* args )
{sleep(1);ThreadData* td =static_cast<ThreadData*>(args);//安全类型转换int cnt=10;while(cnt){cout<<"new thread create success, name: "<<td->namebuffer<<"cnt: "<<cnt--<<endl;sleep(1);}delete td;return nullptr;
}int main()
{//1.创建一批线程vector<ThreadData*> threads;#define NUM 10for(int i=0;i<NUM;i++){
/在这里我们通过new一个对象//ThreadData* td=new ThreadData();
///snprintf(td->namebuffer,sizeof (td->namebuffer),"%s: %d","thread",i+1);//为每个线程设置编号// pthread_t id;//一旦创建成功,就执行上面的执行流
///这里我们将地址td传给pthread_create/pthread_create(&(td->tid),nullptr,start_routine,td);
保证了每一个执行流有自己独立的new对象/threads.push_back(td);sleep(1);}}

🚢:start_routine这个函数现在被十个线程执行,这个函数现在 是重入状态

这个函数是可重入函数吗?答案是的,因为这个函数并没有产生二义性。在函数内部定义的变量叫局部变量,具有临时性。每个线程都有自己独立的栈结构


 2.2pthread_self()获取线程id

 该接口的作用是:获取调用此接口的线程的id,并将id作为返回值。 


 3.线程终止

3.1.return 方式

exit() 能不能用来终止线程呢?答案是不能的,因为exit是终止进程的,任何一个执行流调用exit()都会让整个进程退出。 接下来我们引入一个接口,用来终止线程。

3.2 pthread_exit 

🙂:我们在讲到进程退出的时候,退出是有退出码和退出信号的,为什么在线程这里线程退出的返回值是void 什么都没有呢?

因为线程异常退出,也就是进程退出,所以退出信号是进程该关心的事。  

 4 线程等待

线程也是要被等待的,如果不等待,会造成类似僵尸进程的问题----------内存泄漏

线程等待:

1. 获取线程的退出信息

2.回收新线程对应的PCB等内核资源,防止内存泄漏。

 pthread_join 接口

  for(auto& iter:threads)//遍历threads{   //等待线程int n=pthread_join(iter->tid,nullptr);assert(n==0);cout<<"join: "<<iter->namebuffer<<"success"<<endl;delete iter;}cout<<"main thread quit"<<endl;

测试结果

  接下来我们对pthread_join(pthread_t thread, void **retval)第二个参数进行一下说明。

 

接下来我们对代码做个简单改变,让大家明白第二个参数的使用,pthread _join(pthread_tthread,void** retval)函数是如何获取线程函数的返回结果的。

void* start_routine(void* args )
{ThreadData* td =static_cast<ThreadData*>(args);//安全类型转换int cnt=10;while(cnt){// cout<<"cnt: "<<cnt <<"&cnt"<< &cnt<<endl;// cnt--;// sleep(1);cout<<"new thread create success, name: "<<td->namebuffer<<"cnt: "<<cnt--<<endl;sleep(1);}// delete td;
*******************这是我们的改动return (void*)2;//我们让每个线程函数返回2
}
 for(auto& iter:threads)//遍历threads{//我们想要获取线程函数void*类型的返回结果,要设置一个void*变量void* ret=nullptr;//通过取地址&ret,来取到这个返回结果,所以为什么pthread_join()//第二个参数是void** 类型的,因为其是个输出线参数。int n=pthread_join(iter->tid,&ret);assert(n==0);cout<<"join: "<<iter->namebuffer<<"success: "<<(long long)ret<<endl;delete iter;}

运行结果 

线程控制

创建线程-------->>>>>线程结束----------------->>>>>线程等待


 我们知道对于线程我们为了回收资源不造成内存泄漏,默认情况下都是要进行join的,但是对于我们需要关心线程返回值的情况,必须使用pthread_join()接口函数。如果我们并不关心该线程的返回值,那么其实我们可以不用手动回收线程,可以让其系统自动回收,这就是线程分离 

pthread_detach()

该接口的作用是 将线程与主线程分离,主线程就不管该分离线程的返回值、退出和资源回收情况 。这个接口一般是线程自己调用或者主线程调用


三 理解线程tid 

我们在Linux: 线程概念初识-CSDN博客中说过  int n= pthread_create(&tid,nullptr,thread_routine,(void*)"thread_one");tid是个输出型参数,这个tid的值并不是LWP的值。接下来我们就要对线程的id进行说明,为什么其是一个地址。

🚀:我们在线程概念初识这章节讲过,每个线程都有自己独立的栈结构,这个时候我们会有个疑问?无论有多少个线程,严格来说都在一个进程中,而一个进程有一份程序地址空间,也就是说只有一个栈结构,那么为什么说线程都有自己独立的栈结构呢?

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

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

相关文章

避开养生误区,拥抱健康生活

在追求健康的道路上&#xff0c;我们常常会陷入一些养生误区&#xff0c;不仅无法达到预期效果&#xff0c;还可能损害身体健康。只有拨云见日&#xff0c;认清这些误区&#xff0c;采取正确的养生方式&#xff0c;才能真正拥抱健康生活。​ 很多人认为&#xff0c;保健品吃得…

<数据集>苹果识别数据集<目标检测>

数据集下载链接https://download.csdn.net/download/qq_53332949/90585216数据集格式&#xff1a;VOCYOLO格式 图片数量&#xff1a;535张 标注数量(xml文件个数)&#xff1a;535 标注数量(txt文件个数)&#xff1a;535 标注类别数&#xff1a;2 标注类别名称&#xff1a;…

【补题】P10424 [蓝桥杯 2024 省 B] 好数(数位dp)

题意&#xff1a; 一个整数如果按从低位到高位的顺序&#xff0c;奇数位&#xff08;个位、百位、万位……&#xff09;上的数字是奇数&#xff0c;偶数位&#xff08;十位、千位、十万位……&#xff09;上的数字是偶数&#xff0c;我们就称之为“好数”。 给定一个正整数 N…

分布式存储怎样提高服务器数据的安全性?

分布式存储是一种计算机数据存储架构&#xff0c;主要是将数据信息分布存储在多台计算机或者是服务器上&#xff0c;以此来实现高可靠性、可扩展性和高性能&#xff0c;让每个计算机或服务器可以通过网络连接相互通信和协作。 分布式存储系统会定期对重要的数据信息进行完整性检…

数字IC后端培训教程系列之PR Innovus工具写出Calibre LVS用的Netlist详细步骤

在数字IC后端设计实现chipfinish阶段需要写出很多数据&#xff0c;比如netlist&#xff0c;def&#xff0c;gds&#xff0c;lib和lef等文件。 今天给大家分享PR工具Innovus写出Calibre物理验证LVS要用的netlist的详细步骤。 手把手教你debug解决物理验证Calibre LVS错误 1&a…

TrueNAS scale(23.10) Restful API接口调用

背景 本文主要讲解开源的NAS系统--TrueNAS的二次开发。 TrueNAS scale安装 网上能找到很多类似的文章&#xff0c;本文就不介绍了&#xff0c;这里给一个视频博主的传送门&#xff1a; 司波图 TrueNAS scale Resful API 接口 官网的 Resful API地址&#xff1a;TrueNAS REST…

卡尔曼滤波器浅聊

0 前言: 卡尔曼滤波属于算法领域的,所以一些基本的数学概念是必须了解的 涉及到的数学基本概念 概念数学符号含义数学期望(Expected Value)E描述随机变量平均取值的最核心概念概率(Probability)P(X= x i x_i xi​)随机变量 X 取特定值 x i x_i xi​的概率方差(Varian…

1ll C++

在C++中,1ll 表示 long long 类型的整数常量1。这里的 ll 是 long long 的缩写。这种写法主要用于以下几个方面: 1. 为什么需要 1ll? 在您的代码中,1ll 主要用于 防止整数溢出 和 确保正确的类型转换: cpp 复制 p = 1ll * p * i % MOD; f[i + 1] = 1ll * i * (i + 1) …

oracle 12c密码长度,复杂度查看与设置

一 密码长度和复杂度 Oracle 数据库通过 PASSWORD_VERIFY_FUNCTION 来控制密码复杂度。 1.1 查看当前的密码复杂度设置 SELECT * FROM dba_profiles WHERE resource_name PASSWORD_VERIFY_FUNCTION; LIMIT表示分配给该 PROFILE 的密码验证函数名称。如果为 NULL&#xff0c;…

指定运行级别

linux系统下有7种运行级别,我们需要来了解一下常用的运行级别,方便我们熟悉以后的部署环境,话不多说,来看. 开机流程&#xff1a; 指定数级别 基本介绍 运行级别说明: 0:关机 相当于shutdown -h now ⭐️默认参数不能设置为0,否则系统无法正常启动 1:单用户(用于找回丢…

Appium工作原理及环境的搭建(1)

1、Appium的介绍&#xff1a; 一、什么是Appium Desktop&#xff1f; Appium Desktop是Appium项目的桌面版GUI工具&#xff0c;提供了一个友好的界面&#xff0c;用于启动Appium服务器、查看设备日志、与设备交互、调试自动化脚本等。相比于命令行工具&#xff0c;Appium Des…

esp32cam远程图传:AI Thinker ESP32-CAM -》 服务器公网 | 服务器 -》 电脑显示

用AI Thinker ESP32-CAM板子访问公网ip的5112端口并上传你的摄像头拍摄的图像视频数据&#xff0c;并写一段python程序打开弹窗接受图像实现超远程图像传输教程免费 1. 首先你要有一个公网ip也就是去买一台拥有公网的服务器电脑&#xff0c;我买的是腾讯云1年38元的服务器还可…

【Pandas】pandas DataFrame copy

Pandas2.2 DataFrame Conversion 方法描述DataFrame.astype(dtype[, copy, errors])用于将 DataFrame 中的数据转换为指定的数据类型DataFrame.convert_dtypes([infer_objects, …])用于将 DataFrame 中的数据类型转换为更合适的类型DataFrame.infer_objects([copy])用于尝试…

缓存相关问题

Redis 持久化机制 缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级等问题 热点数据和冷数据是什么 Memcache与Redis的区别都有哪些? 单线程的redis为什么这么快 redis的数据类型,以及每种数据类型的使用场景,Redis 内部结构 redis的过期策略以及内存淘汰机制 Redis 为什么…

2025年AI开发学习路线

目录 一、基础阶段&#xff08;2-3个月&#xff09; 1. 数学与编程基础 2. 机器学习入门 二、核心技能&#xff08;3-4个月&#xff09; 1. 深度学习与框架 2. 大模型开发&#xff08;重点&#xff09; 三、进阶方向&#xff08;3-6个月&#xff09; 1. 多模态与智能体…

SvelteKit 最新中文文档教程(19)—— 最佳实践之身份认证

前言 Svelte&#xff0c;一个语法简洁、入门容易&#xff0c;面向未来的前端框架。 从 Svelte 诞生之初&#xff0c;就备受开发者的喜爱&#xff0c;根据统计&#xff0c;从 2019 年到 2024 年&#xff0c;连续 6 年一直是开发者最感兴趣的前端框架 No.1&#xff1a; Svelte …

【Kafka基础】消费者命令行完全指南:从基础到高级消费

Kafka消费者是消息系统的关键组成部分&#xff0c;掌握/export/home/kafka_zk/kafka_2.13-2.7.1/bin/kafka-console-consumer.sh工具的使用对于调试、测试和监控都至关重要。本文将全面介绍该工具的各种用法&#xff0c;帮助您高效地从Kafka消费消息。 1 基础消费模式 1.1 从最…

CausalML 基于机器学习算法的因果推理方法

CausalML 是一个 Python 包&#xff0c;它使用基于最新研究的机器学习算法提供一套提升建模和因果推理方法。它提供了一个标准界面&#xff0c;允许用户从实验或观察数据中估计条件平均处理效应 &#xff08;CATE&#xff09;&#xff0c;也称为个体治疗效应 &#xff08;ITE&a…

解锁深度学习激活函数

在深度学习的广袤天地里&#xff0c;激活函数宛如隐匿于神经网络架构中的神奇密码&#xff0c;掌控着模型学习与表达的关键力量。今天&#xff0c;就让我们一同深入探究这些激活函数的奇妙世界&#xff0c;揭开它们神秘的面纱。 一、激活函数为何不可或缺&#xff1f; 想象一…

从零到有的游戏开发(visual studio 2022 + easyx.h)

引言 本文章适用于C语言初学者掌握基本的游戏开发&#xff0c; 我将用详细的步骤引领大家如何开发属于自己的游戏。 作者温馨提示&#xff1a;不要认为开发游戏很难&#xff0c;一些基本的游戏逻辑其实很简单&#xff0c; 关于游戏的开发环境也不用担心&#xff0c;我会详细…