『 Linux 』线程概念

文章目录

    • 什么是线程
    • 执行流
    • 线程与进程的关系
    • 页表构造及线程资源分配
    • 线程的轻量化
    • 线程的特点


什么是线程

线程本质上是进程的一个执行分支,用于处理进程中的代码和数据;

每个线程都可以执行独立不同的代码片段,这意味着在一个进程中可以同时执行多个任务;

同一个进程中的所有线程共享相同的内存地址空间和资源(如全局变量,文件句柄等);

使得线程之间的通信和数据共享十分搞笑,因为它们不需要像进程通信那样复杂的机制;

  • 在Linux中,线程在进程"内部"执行,线程在进程的地址空间内运行

    任何执行流要执行的前提是具有资源;

    进程地址空间是进程的资源窗口,线程在进程"内部"执行意味着其将执行进程代码的一部分;

  • 在Linux中,线程的执行粒度要比进程更细

    线程执行进程代码的一部分,所以其执行粒度要比进程更细;

每个进程在创建时会默认包含一个线程,这个线程通常称为主线程;

主线程负责执行进程的主要代码逻辑;

本质上CPU无法区分执行的是线程还是进程;

对于CPU而言只存在执行流的概念;

在计算机组成和操作系统实现中,线程必须被管理和调度,这表明线程需要有对应的数据结构来保存其状态和相关信息;

  • 线程控制块(TCB结构体)

    线程控制块是用于存储线程的状态信息的数据结构,其一般包含以下内容:

    • 线程ID

      唯一标识线程的ID;

    • 程序计数器PC

      保存线程当前执行的指令地址;

    • 寄存器集合

      保存线程运行时的CPU寄存器状态;

    • 堆栈指针

      指向线程的堆栈;

    • 线程状态

      如就绪,运行,阻塞等状态;

    • 线程优先级

      线程的优先级信息;

    • 调度信息

      用于线程的调度的相关信息;

在Linux中,线程的实现采用的是复用进程的task_struct结构体;

每个进程和线程在内核中都用一个task_struct结构体实例来表示;


执行流

执行流是指CPU按照指令顺序逐条执行的过程,它可以来源于进程或线程;

CPU在运行时不区分其执行的指令是属于进程还是线程,其只进行逐条执行指令,并根据指令执行结果更新程序计数器和相关寄存器;

  • 调度器

    操作系统调度器负责决定哪个执行流在某个时刻被分配到CPU上执行;

    调度器管理进程控制块(PCB)和线程控制块(TCB),在Linux中统一使用task_struct;

  • 上下文切换

    当调度器决定和切换执行流时将会保存当前执行流的上下文,如寄存器程序计数器等,并恢复下一个执行流的上文;

线程是更细粒度的执行单元,多个线程共享统一进程的地址空间和资源但其个字拥有独立的执行流;

CPU的视角看,不管是进程还是线程都只是一个需要被执行的指令序列,即执行流;

CPU至按照调度器的指令执行下一个指令序列而不关心其所属的进程或线程;

  • 线程<=执行流<=进程

    当执行流是线程时,其<=进程;

    当执行流是进程时,其>=线程;

    所以可以称为 线程<=执行流<=进程 ;

故在Linux中的执行流可以被称为 “轻量级进程” ;


线程与进程的关系

一个进程中可以包含多个线程,这表明一个进程中线程的数量必须>=1;

本质上进程为其对应的代码和数据的结合;

  • 进程

    进程是操作系统中资源分配和管理的基本单位;

    这些资源包括内存空间,进程控制块(PCB结构体),打开的文件描述符,信号处理机制等;

    每个进程都有自己独立的内存空间,打开的文件,信号处理方式等;

    进程之间是相互独立的,一个进程的崩溃不会影响到其他进程;

  • 线程

    线程是进程中的一个执行单元,也称为轻量型进程;

    线程是操作系统中能够进行运算调度的最小单位;

    同一个进程中的所有线程共享该进程的资源,如进程地址空间,全局变量,文件句柄等;

    对应的线程也需要独立的属性和数据使其能够被操作系统管理,包括其具有独立的程序计数器,寄存器集合和栈;

一个进程至少包含一个线程,即主线程;

主线程负责执行代码的主要代码逻辑;

一个进程可以创建多个线程,这些线程共享进程的资源和地址空间;

线程本质上是进程内部的执行流资源;


页表构造及线程资源分配

一个进程存在着对应的PCB结构体(task_struct);

task_struct中包含着指向进程地址空间的指针,即间接指向进程地址空间;

进程地址空间通过页表映射至物理内存,当在处理一个进程的上下文时对应的CR3寄存器将会指向这个页表,即存放该页表的物理地址;

当需要访问一个物理地址时MMU寄存器将通过页表将虚拟地址转化为具体物理地址;

页表本质上是以分页的形式进行存放的从而大大减少了占用空间的开销;

32位虚拟地址为例,其将32位虚拟地址分别以10 + 10 + 12的形式进行存储,其分别为页目录(10位),页表(10位)和页内偏移量(12位);

其每十位或是十二位都可以由全0到全1进行存储,当需要转化时将会将其转化为对应的十进制从而进行索引;

  • 页目录

    页目录中存在2^10个页目录表项,即1024个页目录表项;

    其中每个页目录表项包含着每个页目录的页表的索引;

    32位虚拟地址的前十位可索引到对应的页目录表项从而索引页表;

  • 页表

    也被称为二级页表,存在2^10个页表表项,即1024个页表表项;

    每个页表表项包含着物理内存的页号;

    32位虚拟地址的中间十位可索引到对应页号的页初始地址;

  • 物理内存

    物理内存中将以 作为最小访问单位,一般情况下一个页的大小为4kb2^12字节;

    12次方可对应着32位虚拟内存中的最后12位;

当一个执行流需要访问物理内存时本质上是从CR3中访问到对应的页目录,通过前10位的十进制转换找到对应的页目录表项并索引到对应的页表;

再利用中间10位转换为十进制访问该页表找到对应的页表表项,并根据对应的页号找到物理内存的页;

最后通过32位虚拟地址的最后12位索引到页中的具体位置从而进行访问;

  • 页表的大小

    一般情况下,页目录表项与页表表项的大小都为4byte;

    一个页目录存在1024个页目录表项,即4 * 1024byte4kb;

    一个页表存在1024个页表表项,且一个页目录存在1024个页表,即4 * 1024 * 1024byte4mb;

    最终大小为4kb + 4mb(一个进程);

而实际上一个进程不是所有页表(二级页表)的页表表项都会被使用,故一个进程的页表(进程页表)大小为<= 4kb + 4mb;

当对一个int类型的地址进行取地址时获取到的地址本质上是段基地址,即该数据块的起始地址;

X86计算机中本质上 起始地址 + 类型 就是 起始地址 + 偏移量 ;

同时在计算机中,无论使用何种复杂的数据结构类型,这些数据最终都会被转换为由内置类型(int,float,char等)组成的数据块;

这些基本数据类型定义了数据在内存中的具体布局和操作方式,编译器通过这些基本数据类型生成底层的机器代码;

  • CR2寄存器

    该寄存器是一个在X86计算机上的控制寄存器;

    专门用于存储导致最近一次的缺页异常的线性地址(虚拟地址);

    CPU 访问一个未映射的虚拟地址或没有适当权限访问的地址时,会触发缺页中断;

    处理器将导致缺页中断的虚拟地址存储在 CR2 寄存器中,然后将控制权转移到缺页中断处理程序;

    操作系统的缺页中断处理程序可以使用 CR2 寄存器中的地址来确定哪个页导致了缺页中断,并采取相应的措施,如加载缺失的页到内存中或终止进程;

本质上线程的资源分配就是分配地址空间范围;

操作系统为每个线程分配一个独立的虚拟地址空间,保证每个线程可以独立运行而互不干扰;

  • 共享的虚拟地址空间

    • 代码段

      线程共享进程的代码段,即可执行指令;

    • 数据段

      线程共享进程的数据段,包括已初始化和未初始化的全局变量和静态变量;

    • 线程共享进程的堆区,用于动态内存分配;

      多个线程可以同时分配和实施方内存(需要同步互斥机制避免竞争);

  • 独立的栈空间

    每个进程有自己独立的栈,用于函数调用和局部变量的存储;

    • 栈分配

      操作系统在创建线程时会为其分配独立的栈空间;

      栈空间大小通常是固定的(某些操作系统可配置线程的栈的大小);

    • 栈增长

      栈通常从高地址向低地址增长;


线程的轻量化

线程较进程更加轻量化的具体表现为以下几点:

  • 创建

    • 进程

      在创建一个进程时操作系统需要进新的虚拟地址空间分配,包括代码段,数据段,堆栈等;

      创建进程控制块包含进程的所有信息;

      初始化文件描述符表,复制父进程的文件描述符;

      进行资源分配和权限设置;

      一般情况下可用fork()创建进程,将会复制整个进程的上下文包括进程地址空间;

    • 线程

      创建一个新线程时操作系统将分配一个新的栈空间;

      创建线程控制块(Linux依旧为task_struct)用于包含线程信息;

      对于进程地址空间而言线程共享进程的进程地址空间;

      一般情况下线程的创建只需要分配栈和对应的TCB结构体;

  • 切换(上下文切换)

    • 进程切换

      在进行进程切换的过程中需要进行上下文保存,包括CPU寄存器,程序计数器,栈指针,虚拟地址空间等;

      更改CR3寄存器的页表指针以切换虚拟地址空间;

      为保证内存访问的一致性,由于页表切换导致的地址空间变化需要刷新TLB和部分缓存(cache),该操作表明数据需要再次进行一次由冷到热的过程;

      进程切换设计大量状态信息的保存与恢复,以及页表切换,开销较大;

    • 线程切换

      保存当前运行线程的寄存器状态和栈指针;

      由于线程共享进程的虚拟地址空间,所以无需切换页表;

      同时线程切换不涉及虚拟地址空间的改变,其TLBcache缓存不需要刷新,意味着不需要使数据再次经过一个由冷到热的过程以保持了缓存的一致性和效率;

      恢复即将运行线程的寄存器和栈指针;

      线程切换仅涉及寄存器状态和栈指针的保存和恢复,总体开销较小;

  • 销毁

    • 进程销毁

      进程在销毁时需要回收进程占用的所有资源,包括内存,文件描述符等,需要全面对进程的资源进行清理;

    • 线程销毁

      线程在销毁时只需要回收线程的栈空间与TCB,仅需清理线程相关资源;


线程的特点

线程的优点为以下几点:

  • 创建代价低

    创建一个新的线程的代价比创建一个新进程要小;

    线程共享大部分的进程资源,创建时只需要分配新的栈空间和对应的线程控制块即可;

  • 切换开销小

    与进程切换想必,线程之间的切换需要操作系统做的工作要少;

    切换避免了大量数据的重新预加载;

  • 占用资源少

    线程的占用资源比进程少,其共享进程的虚拟地址空间和其他资源从而减少了内存和资源的占用;

  • 利用多处理器并行

    线程能充分利用多处理器的并行能力;

    通过将计算任务分解到多个线程中从而在多处理器系统上执行多个线程而提高计算效率;

  • 提高I/O性能

    在等待慢速I/O操作结束的同时,线程可以执行其他计算任务;

    提高程序的并行性和响应速度;

  • 计算密集型应用

    在计算密集型应用中可将计算任务分解为多个线程;

    可在多处理器系统上并行执行以提高整体计算能力;

  • I/O密集型应用

    I/O密集型应用中,通过将I/O操作重叠执行,不同的线程可以同时等待不同的I/O操作从而提高I/O性能;

其缺点为以下几点:

  • 性能损失

    对于很少被外部事件阻塞的计算密集型线程无法与其他线程共享同一个处理器;

    如果计算密集型线程的数量超过可用的处理器则会增加额外的同步和调度开销导致性能损失;

  • 健壮性降低

    线程之间的共享数据可能会导致同步问题和竞态条件;

    增加了程序的不确定性和复杂性从而出现难以调试的错误;

  • 缺乏访问控制

    线程共享进程的所有资源,意味着一个线程的错误可能会影响整个进程的稳定性;

  • 编程难度提高

    在进行多线程编程的开发中需要处理线程同步,死锁和竞态条件等问题;

    对应的编程难度提高;

同时在多线程程序中,由于线程是进程的一部分,若是该进程中的一个线程崩溃(除零错误,野指针等问题)将影响到整个进程;

线程异常通常会触发进程的信号机制从而使得整个进程退出,相应的所有线程也会随之退出;

线程通常用来进行 CPU密集型程序I/O密集型程序 的开发;

  • CPU密集型程序

    多线程可以提高CPU密集型程序的效率;

    通过并行处理,可以利用多核处理器的能力加快任务完成的速度从而提升效率;

  • I/O密集型程序

    I/O密集型程序中使用多线程,可以在等待I/O操作时执行其他任务从而提高程序的相应速度和用户体验;

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

基于微信小程序+SpringBoot+Vue的社区超市管理系统(带1w+文档)

基于微信小程序SpringBootVue的社区超市管理系统(带1w文档) 基于微信小程序SpringBootVue的社区超市管理系统(带1w文档) 为了让商品信息的管理模式进行升级&#xff0c;也为了更好的维护商品信息&#xff0c;社区超市管理系统的开发运用就显得很有必要&#xff0c;因为它不仅可…

全球奈拉滨市场规模预测:未来六年年复合增长率CAGR为1.1%

据恒州诚思研究&#xff0c;2023年全球奈拉滨市场规模大约为3.8亿元&#xff0c;预计未来六年年复合增长率CAGR为1.1%&#xff0c;到2030年市场规模将接近4.2亿元。这一增长反映了奈拉滨在全球医药行业中的重要性及其在未来发展中的潜在机会。随着科学的进一步发展和市场的扩展…

全网最详细Gradio教程系列5——Gradio Client: curl

全网最详细Gradio教程系列5——Gradio Client: curl 前言本篇摘要5. Gradio Client的三种使用方式5.3 Curl查询Gradio Apps5.3.1 安装5.3.2 获取Gradio程序的URL5.3.3 HF_TOKEN和身份认证1. POST/GET示例2. 整合命令&#xff1a;awk和read3. HF_TOKEN4. 身份认证 5.3.4 POST&am…

21 Python常用内置函数——zip()

zip() 函数用来把多个可迭代对象中的元素压缩到一起&#xff0c;返回一个可迭代的 zip 对象&#xff0c;其中每个元素都是包含原来的多个可迭代对象对应位置上元素的元组&#xff0c;最终结果中包含的元素个数取决于所有参数序列或可迭代对象中最短的那个。 可以这样理解这个函…

WPF启动失败报System.Windows.Automation.Peers.AutomationPeer.Initialize()错误解决

问题描述 win10系统上WPF程序启动后就崩溃&#xff0c;通过查看崩溃日志如下&#xff1a; 应用程序: xxx.exe Framework 版本: v4.0.30319 说明: 由于未经处理的异常&#xff0c;进程终止。 异常信息: System.TypeLoadException 在 System.Windows.Automation.Peers.Automatio…

强者具备的三个思维

强者具备的三个思维&#xff0c;看看你占了几条&#xff1f; 一、不看自己需要什么&#xff0c;而是看环境和别人需要什么。满足他们&#xff0c;你就能把事情做成。 二、不追求稳定&#xff0c;而是享受不稳定。稳定的工作和生活&#xff0c;并不意味着你的技能已经娴熟。而…

SpringBoot上传超大文件导致Cannot read more than 2,147,483,647 into a byte array,问题解决办法

问题描述 报错: java.lang.IllegalArgumentException: Cannot read more than 2,147,483,647 into a byte array at org.apache.commons.io.IOUtils.lambda$toByteArray$0(IOUtils.java:2403) ~[commons-io-2.11.0.jar:2.11.0] at org.apache.commons.io.output.Thre…

C++学习日记 | LAB 10 运算符重载与友元函数

资料来源&#xff1a;南科大 于仕琪 C/C Program Design LINK&#xff1a;CPP/week10 at main ShiqiYu/CPP GitHub 一、本节内容 本节首先以一个例子具体演示和回顾操作符重载、友元函数以及重载<<操作符。习题部分则为各种运算符重载以及输入输出重载 1.1 Operator o…

支持向量机回归及其应用(附Python 案例代码)

使用支持向量机回归估计房价 让我们看看如何使用支持向量机&#xff08;SVM&#xff09;的概念构建一个回归器来估计房价。我们将使用sklearn中提供的数据集&#xff0c;其中每个数据点由13个属性定义。我们的目标是根据这些属性估计房价。 引言 支持向量回归&#xff08;SV…

WHAT - 一个 Github 仓库的 License 如何解读

目录 一、背景二、解读许可证说明的作用常见的开源许可证类型使用他人代码仓库时需要注意的事项结论 实践作为开发者1. 选择许可证类型2. 在 README 文件中编写许可证信息 作为使用者1. 确定权限2. 了解和遵守条款 总结 一、背景 我们经常在一些 Github 仓库里看到 License 部…

Cache 替换策略--PLRU算法详解

一、引言 LRU&#xff08;Least Recently Used&#xff09;是 cache 的经典替换策略之一&#xff0c;但当 Cache 的路数比较大时&#xff08;多路组相连结构&#xff09;&#xff0c;实现 LRU 的硬件开销就会变得很大。现代处理器一般会考虑使用 PLRU&#xff08;pseudo-LRU&a…

Vue.js 2 项目实战(八):小黑记事本组件版

前言 Vue.js 是一个用于构建用户界面的渐进式 JavaScript 框架。它的设计初衷是通过采用简洁且强大的结构&#xff0c;使前端开发变得更简单和高效。以下是对 Vue.js 的详细介绍&#xff1a; 核心特性 声明式渲染 Vue.js 使用声明式语法来描述用户界面&#xff0c;通过数据绑…

用Swagger进行后端接口测试的实战操作

目录 一.什么是Swagger&#xff1f; 二.Swagger的使用操作流程&#xff1a; 1.在pom.xml配置文件导入 Knife4j 的依赖&#xff1a; 2.在config配置类中加入 Knife4j 的相关配置并设置静态资源映射&#xff08;否则接口文档无法访问&#xff09;&#xff1a; 三.Swagger的四个…

xctf--debug

第一眼看着给我吓了一跳 我还以为是什么很牛逼壳 结果就是dnspy打开 这个函数什么ID都没有 只能一个一个点 但是逻辑真的很清晰 之前BUU写的题太复杂了,感觉可以看看这些题静下心 这个时候看着 攻防世界逆向高手题之debug_攻防世界debug-CSDN博客 这个博主的(我好多东西…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 亲子游戏(200分) - 三语言AC题解(Python/Java/Cpp)

🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试D卷目录,全、新、准,题目覆盖率达 95% 以上,支持题目在线…

【轨物方案】电气设备数字档案解决方案

需求痛点 传统的电气设备铭牌只能显示固定的名称、日期、型号等信息&#xff0c;不能把与设备相关的其他重要信息展现出来&#xff0c;终端用户想要了解设备信息比较困难。尤其像项目资料类的文件查看&#xff0c;更是有很多不便之处&#xff0c;当设备出现问题后&#xff0c;找…

简要了解sql注入

sql注入安全测试中危害 数据库中的数据&#xff0c;对数据库数据进行操作&#xff08;查询、删除等&#xff09;&#xff1b;网站的权限&#xff0c;找到注入点后可后门写入&#xff1b; sql注入产生原理详细分析 可控变量&#xff0c;带入数据库查询&#xff0c;变量未存在…

前后端打包部署 虚拟机jdk安装及配置环境变量 +安装nginx

mkdir deploy ll mkdir gateway auth system file 去idea打包 不要先打gateway 上传上去 出现这个问题是因为你jdk环境不一样 我的是17 所以我现在去官网下载一个 官网 &#xff1a;Java Downloads | Oracle 中国 mkdir software cd software/ wget https://download.oracl…

橙单前端项目下载编译遇到的问题与解决

今天下载orange-admin前端项目&#xff0c;不过下载下来运行也出现一些问题。 1、运行出现下面一堆错误&#xff0c;如下&#xff1a; 2、对于下面这个错误 error Expected linebreaks to be LF but found CRLF linebreak-style 这就是eslint的报错了&#xff0c;可能是原作者…

目标检测自顶向下入门

最近在学习Yolo和OpenCV这些计算机视觉的相关领域&#xff0c;把深度学习啃了个大概&#xff0c;准备着手学习一下Yolov5&#xff0c;趁着这个机会入门一下目标检测这个领域&#xff0c;也算是自顶向下地学习一遍吧。 目标检测 什么是目标检测 物体识别&#xff08;Object de…