【Linux线程】——线程概念线程接口

目录

前言

1.线程

2.线程的本质

3.Linux线程库

3.1创建线程——pthread_create

3.2线程终止——pthread_exit

3.3线程等待——pthread_join

3.4线程分离——pthread_detach

3.5获取线程tid——pthread_self

4.线程的优缺点

4.1线程的优点

4.2线程的缺点

结语


前言

  在当今复杂而高效的计算机系统中,多任务处理已经成为了不可或缺的核心能力。Linux操作系统以其卓越的性能和广泛的适应性,成为了众多开发者和系统管理员的首选平台。

  而线程,作为进程中的执行单元,是实现多任务并发执行的关键技术之一。Linux线程的实现机制为开发者提供了丰富的工具和接口,使得我们能够充分利用系统资源,提高程序的运行效率和响应速度。

  本文将深入探讨Linux线程的相关概念、原理和实践应用,为读者呈现一个全面而深入的Linux线程技术体系。 


1.线程

线程是调度的基本单位,是轻量化的进程,是依附进程存在的产物

一个进程内部可以有多个线程,一个线程就是一个执行流,负责执行进程分配的任务

我们常说CPU调度进程,而在相应的进程获得CPU调度,得到时间片,这个时间片会再度被内部的线程进行瓜分,所以,线程才是CPU调度的基本单位

为什么会有线程呢?

父进程创建子进程的目的——让子进程完成其他任务

同理,创建线程的初衷也是如此,线程是一个执行流,可以异步完成进程交付的任务

但我们创建一个子进程不行吗?为什么还要线程?

进程的创建、切换、销毁、存在着大量的时空开销,为了减少这部分开销,提高工作效率,就创建了线程!

从创建上提高:

  1. 创建一个进程,操作系统会为其分配一个程序地址空间
  2. 创建一个线程,直接让其使用进程的程序地址空间

从切换上提高:

  1. 旧进程换出,新进程换入,寄存器会替换一套完整的进程上下文,但在实际当中,根据局部性原理,有一些进程的上下文是其实是存在相同的,有一部分寄存器也就不用替换
  2. 进程仍是一意孤行,这样就会多出来一部分CPU与内存的交互,增加时间开销
  3. 线程则是能省则省,减少了一部分寄存器的替换,减少了一部分时间开销

我们经常提到多线程,而不提多进程,就是这个原因,使用多线程比使用多进程更加高效率,更加优雅

简单总结一下:

线程是轻量化的进程,是进程内部一个独立的执行流,可以异步完成任务,且效率更高

2.线程的本质

先说结论:

线程的本质就是一个函数的运行

可以说,原来没有进程,有了线程,也便有了进程

我们常说的main函数,是程序的入口,是进程的起点,其实也是线程的起点

只不过这个线程比较特殊,是进程的第一个线程,我们将其称为主线程

主线程可以创建其他线程

正如主线程的入口是main函数,其他线程入口也是一个函数

而线程的运行,就是函数的运行,创建一个线程,本质上也是调用一个函数,只不过这个函数的调用并不是和主线程同步的,而是异步!

线程的资源分配

线程不会有自己的程序地址空间,而是从进程地址空间分配,那么哪些资源会被线程共享,哪些资源是线程自己的呢?

直接紧扣字眼,记住:线程的本质是函数的运行,线程CPU调度的基本单位

什么是线程私有的?

  1. 线程的本质是函数的运行,当函数被调用的时候,会有自己的函数栈帧,上面有函数运行所需要的一切,同理,线程也会有自己的栈区,即,线程的栈区是私有化的
  2. 线程是CPU调度的基本单位,当被CPU调度的时候,会有一套寄存器内容,这套内容即是线程的上下文,调出带走,调入带进,即线程上下文是私有的

什么是线程共有的?

在main外定义一个函数,这个函数内部可以使用外部的什么?

全局变量、static变量、函数等

答案也显而易见,main函数外的普通函数可以共享什么,线程就可以共享什么

代码区、静态区、堆区都是每个线程可以访问并使用的,不过有读写的限制

3.Linux线程库

已经理解了什么是线程,以及它的特点,接下来看看如何使用

在Linux系统中,有多种线程库可供使用,其中最常用的是POSIX线程库(也称为Pthreads)。Pthreads是一个遵循POSIX标准的线程库,它提供了一组丰富的函数和数据类型,用于创建、管理和同步线程。

下面介绍一些常用的Pthreads接口及其功能

3.1创建线程——pthread_create

pthread_create函数用于创建一个新的线程,包含于头文件<pthread.h>中

函数造型:

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

参数说明: 

  • hread:用于存储新创建线程的线程ID。
  • attr:线程属性对象,通常可以设置为NULL,表示使用默认属性。
  • start_routine:线程启动后要执行的函数指针。
  • arg:传递给线程函数的参数。

返回值说明:

  • 返回值为0,则创建成功
  • 返回值为-1,则创建失败,并重置error全局变量

基本使用:

void *print_hello(void *arg) {printf("Hello from thread!");return NULL;
}int main() {pthread_t thread;int ret = pthread_create(&thread, NULL, print_hello, NULL);if (ret!= 0) {perror("pthread_create");return 1;}
}

使用技巧:

线程的本质就是函数的运行,就将创建线程当成异步调用函数即可,定义函数时,就将其当成main来写即可,线程并不是很高大尚的东西,紧扣字眼就不难

3.2线程终止——pthread_exit

pthread_exit用于终止一个线程的执行,包含于头文件<pthread.h>中

函数造型:

void pthread_exit(void *retval);

参数说明:

  • retval:线程的返回值,可以被其他等待该线程结束的线程获取。

  • ​**pthread_join函数**:用于等待指定线程结束并获取其返回值。其原型如下:

基本使用:

void *print_hello(void *arg) {printf("Hello from thread!");void* ret_value = new void;pthread_exit(ret_value);return NULL;
}

 注意:

这个参数并不是创建者调用的,而是需要终止的线程自己调用的,相当于“我终结我自己”,函数成功后,会将线程的返回值保存在指针中,由其他线程获取

3.3线程等待——pthread_join

我们创建线程的目的是为了让新的线程完成其他任务
不仅要交付给线程这个任务,我们还需要这个任务被线程完成得怎么样。

对一个线程,需要获取线程的结果

已经退出的线程,其空间没有被释放,仍然在进程的地址空间内,会一直占据这部分空间。
当新的进程被创建,就不会复用这部分空间,

对一个线程,我们需要主动回收已经退出的进程的空间资源,防止空间泄露

为了完成上面两个目标,我们可以使用线程库中的 pthread_join函数 一键完成

pthread_join 函数是 POSIX 线程(Pthreads)库中用于等待指定线程结束并获取其返回值的重要函数。它在多线程编程中扮演着关键角色,确保主线程能够正确地同步和回收子线程的资源。

函数造型:

int pthread_join(pthread_t thread, void ​**retval);

参数说明:

  • thread(pthread_t 类型): 要等待结束的线程的线程 ID。
  • retval(void ​** 类型): 指向一个 void * 指针的指针,用于存储被等待线程通过 pthread_exit 返回的值。如果不需要获取返回值,可以将其设置为 NULL

返回值说明:

  • 成功时: 返回 0
  • 失败时: 返回错误码,常见的错误码包括:

注意:

pthread_join函数一般是创建新线程的线程使用的,即一般使用者都是主线程 

3.4线程分离——pthread_detach

使用pthread_join等待指定线程的目的之一——知晓线程执行任务的结果

倘若我们并不关心一个线程的执行任务的结果,此时用pthread_join进行等待实际上就是一种负担,此时就可以使用pthread_detach函数对目标线程进行分离

pthread_detach函数在 POSIX 线程(Pthreads)库中用于将一个线程设置为“分离状态”,处于分离状态的线程在终止时会自动释放其资源,主线程无法也不需要通过 pthread_join 来回收其资源。

函数造型:

int pthread_detach(pthread_t thread);

参数说明:

  • thread(pthread_t 类型): 要设置为分离状态的线程的线程 ID。

返回值说明:

  • 成功时: 返回 0
  • 失败时: 返回错误码

注意:

线程分离可以是主线程将目标线程分离,也可以是线程主动将自己分离

3.5获取线程tid——pthread_self

pthread_self 是 POSIX 线程(Pthreads)库中的一个函数,用于获取调用线程的线程 ID。

每个线程在创建时都会被分配一个唯一的线程 ID,pthread_self 可以用来获取当前线程的这个 ID。

函数造型

pthread_t pthread_self(void);

返回值

  • 返回值类型pthread_t

注意:

返回调用线程的线程 ID。这是一个不透明的数据类型,具体实现可能因系统而异。

4.线程的优缺点

凡事都有两面性,对待线程我们也不能光看它的优点

需要辩证地看待它

4.1线程的优点

  • 创建一个新线程的代价要比创建一个新进程小得多
  • 与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多
  • 线程占用的资源要比进程少很多
  • 能充分利用多处理器的可并行数量
  • 在等待慢速I/O操作结束的同时,程序可执行其他的计算任务
  • 计算密集型应用,为了能在多处理器系统上运行,将计算分解到多个线程中实现
  • I/O密集型应用,为了提高性能,将I/O操作重叠。线程可以同时等待不同的I/O操作。

4.2线程的缺点

  • 性能损失:一个很少被外部事件阻塞的计算密集型线程往往无法与其它线程共享同一个处理器。如果计算密集型线程的数量比可用的处理器多,那么可能会有较大的性能损失,这里的性能损失指的是增加了额外的同步和调度开销,而可用的资源不变。
  • 健壮性降低:编写多线程需要更全面更深入的考虑,在一个多线程程序里,因时间分配上的细微偏差或者因共享了不该共享的变量而造成不良影响的可能性是很大的,换句话说线程之间是缺乏保护的。
  • 缺乏访问控制:进程是访问控制的基本粒度,在一个线程中调用某些OS函数会对整个进程造成影响。
  • 编程难度提高:编写与调试一个多线程程序比单线程程序困难得多。

结语

  本文对Linux线程做了一个简要的概述,希望能让读者对Linux线程的基本概念和操作有了一定的了解。线程技术是Linux编程中不可或缺的一部分,在今后的学习和实践中,希望大家都能继续深入研究,将其运用到实际的开发项目中。以上就是本文的全部内容,感谢大家的阅读。

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

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

相关文章

机器学习——KNN超参数

sklearn.model_selection.GridSearchCV 是 scikit-learn 中用于超参数调优的核心工具&#xff0c;通过结合交叉验证和网格搜索实现模型参数的自动化优化。以下是详细介绍&#xff1a; 一、功能概述 GridSearchCV 在指定参数网格上穷举所有可能的超参数组合&#xff0c;通过交叉…

STM32基础教程——定时器

前言 TIM定时器&#xff08;Timer&#xff09;:STM32的TIM定时器是一种功能强大的外设模块&#xff0c;通过时基单元&#xff08;包含预分频器、计数器和自动重载寄存器&#xff09;实现精准定时和计数功能。其核心原理是&#xff1a;内部时钟&#xff08;CK_INT&#xff09;或…

[特殊字符] 树莓派声卡驱动原理全解析:从模拟耳机口到HiFi DAC

一、为什么要关注树莓派的声卡驱动&#xff1f; 树莓派&#xff08;Raspberry Pi&#xff09;作为一款广泛应用的单板计算机&#xff0c;集成了多种音频输出接口&#xff08;如 3.5mm 耳机、HDMI、I2S 外接 DAC 等&#xff09;。但许多用户在使用中会遇到诸如“耳机输出杂音”…

使用若依AI生成springBoot的前后端分离版本

目录 1. 从Git上面下载前后端分离版本 2. 执行SQL脚本 3. 初始化前端 安装Node.js和npm配置 ✅ 第一步&#xff1a;在 Node 安装目录下创建两个文件夹 ✅ 第二步&#xff1a;配置 npm 全局目录和缓存目录 ✅ 第三步&#xff1a;验证配置是否成功 ✅ 第四步&#xff1a;…

神聖的綫性代數速成例題12. 齊次方程組零解充要條件、其齊次方程組非零解、 齊次方程組基礎解系

1. 綫性空間的定義&#xff1a; 設是一個非空集合&#xff0c;是一個數域。 在集合的元素之間定義了加法運算&#xff0c;即對於任意&#xff0c;有唯一的&#xff0c;使得&#xff1b;在數域與集合的元素之間定義了數乘運算&#xff0c;即對於任意和&#xff0c;有唯一的&am…

万亿级数据量的OceanBase应用从JVM到协议栈立体化改造实现性能调优

本文基于某电商平台亿级商品详情页场景&#xff0c;通过Java应用层与数据库层的协同优化&#xff0c;实现98%的查询响应时间低于50ms。 一、JDBC连接池深度调优 HikariCP配置示例&#xff1a; HikariConfig config new HikariConfig(); config.setJdbcUrl("jdbc:ocean…

腾讯:《详解DeepSeek:模型训练、优化及数据处理的技术精髓》23页|附下载方法

导 读 INTRODUCTION 这是一篇来自腾讯的关于DeepSeek大语言模型及其技术特点、应用场景和未来发展趋势的文章&#xff0c;主要介绍了DeepSeek的核心技术优势、行业应用案例以及在AI领域的竞争力和发展趋势。为理解DeepSeek大语言模型的技术优势和应用前景提供了深入的分析&…

Vue 入门到实战 五

第5章 过渡与动画 目录 5.1 单元素/组件过渡 5.1.1 过渡class 5.1.2 CSS 过渡 5.1.3 CSS 动画 5.1.4 同时使用过渡和动画 5.1.5 JavaScript 钩子方法 5.2 多元素/组件过渡 5.2.1 多元素过渡 5.2.2 多组件过渡 5.3 列表过渡 5.3.1 列表的普通过渡 5.3.2 列表的平滑…

L2TP实验

一、拓朴图 二、实验配置 1.基础配置 1.1接口IP及服务配置 [PPPoE Client]interface GigabitEthernet 0/0/0 [PPPoE Client-GigabitEthernet0/0/0]service-manage all permit [NAS]interface GigabitEthernet 0/0/0 [NAS-GigabitEthernet0/0/0]ip add 192.168.0.2 24 [NAS-Gi…

简单实用!百度AI + Raphael AI = 免费生图

简单实用&#xff01;百度AI Raphael AI 免费生图 -- ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/b55eda9141d34697b05db0cd60f62b75.png#pic_center) 第一步&#xff1a;下载或截取一些好看的图片当参考图片 第二步&#xff1a;用百度AI描述你想要的图片&…

aws(学习笔记第三十四课) dockerized-app with asg-alb

文章目录 aws(学习笔记第三十四课) dockerized-app with asg-alb学习内容&#xff1a;1. 整体架构1.1 代码链接1.2 代码手动修改部分1.2.1 rds_stack.py1.2.2 efs_stack.py1.2.3 asg_stack.py1.2.4 userdata.sh 1.2 整体架构 2.代码解析2.1 全体app.py2.2 NetworkStatck网络2.3…

面试总结之 Glide自定义的三级缓存策略

一、为什么需要三级缓存&#xff1f; 在移动应用开发中&#xff0c;图片加载性能直接影响用户体验。根据 Google 统计&#xff0c;图片加载延迟超过 1 秒会导致 32% 的用户流失。传统图片加载方案存在以下痛点&#xff1a; 内存占用高&#xff1a;未压缩的大图直接占用大量内…

用Python实现交互式数据可视化:从基础图表到动态仪表板

用Python实现交互式数据可视化&#xff1a;从基础图表到动态仪表板 一、项目背景 本文将通过一个完整的Python项目&#xff0c;展示如何使用Plotly和ipywidgets构建从基础统计到动态交互的全栈数据可视化方案。 二、核心功能模块 1. 数据生成与预处理 np.random.seed(100)…

Linux进程信号

1.信号的认识 生活中例如闹钟&#xff0c;红绿灯&#xff0c;电话铃声等都属于信号&#xff0c;所白了信号就是中断我们正在做的事情&#xff0c;属于进行事件异步通知机制。 在Linux中信号是发给进程的&#xff0c;信号的产生相较于进程是异步的。 信号的相关知识点&#xff…

Java使用FFmpegFrameGrabber进行视频拆帧,结合Thumbnails压缩图片保存到文件夹

引入依赖 <dependency><groupId>net.coobird</groupId><artifactId>thumbnailator</artifactId><version>0.4.17</version></dependency><dependency><groupId>org.bytedeco</groupId><artifactId>ja…

c++项目-KV存储-模仿redis实现kv键值对存储的基本功能。

KV存储引擎的技术解析&#xff1a;数组、哈希与红黑树实现及其在网络I/O中的应用。 内容概要&#xff1a;本文档深入介绍了基于数组、哈希表和红黑树的键值存储引擎的设计与实现。文档首先阐述了系统的总体架构与类图关系&#xff0c;之后分别对底层存储结构进行了详细解释&am…

vue3:十一、主页面布局(优化页面跳转方式)

:router"true" 一、参考文章 vue3:十一、主页面布局(实现基本左侧菜单右侧内容效果)-CSDN博客 参考上述文章可知&#xff0c;页面跳转是通过在js中定义的菜单中携带的path&#xff0c;然后通过菜单的点击事件完成的跳转&#xff0c;现在可以进行优化&#xff0c;直…

深入解析 Java Stream API:筛选子节点的优雅实现!!!

&#x1f680; 深入解析 Java Stream API&#xff1a;筛选子节点的优雅实现 &#x1f527; 大家好&#xff01;&#x1f44b; 今天我们来聊聊 Java 8 中一个非常常见的操作&#xff1a;使用 Stream API 从 Map 中筛选出特定条件的元素。&#x1f389; 具体来说&#xff0c;我们…

统计学重要概念:自由度

在统计学中&#xff0c;自由度&#xff08;degrees of freedom&#xff0c;简称df&#xff09;是一个重要的概念&#xff0c;它表示在计算某个统计量时可以自由变化的值的数量。对于一个样本量为n的样本&#xff0c;自由度通常为n-1&#xff0c;这是因为我们需要用样本数据来估…

数据结构-排序

文章目录 1. 排序的概念2. 常见排序算法的实现2.1 插入排序1&#xff09;插入排序一&#xff09;基本思想二&#xff09;特性及时间复杂度三&#xff09;代码实现 2&#xff09;希尔排序&#xff08;缩小增量排序&#xff09;一&#xff09;基本思想二&#xff09;特性及时间复…