【Linux线程】线程的深度解析(线程是什么?线程与进程区别是什么?)

目录

一、前言

二、 什么是线程

💧线程的引入💧 

💧线程的基本概念 💧

💧线程的理解 💧 

💧进程与线程的关系💧

💧程序如何划分(重拾页表、见一下LWP)💧 

三、简单的使用线程

四、线程小结 

🔥再谈线程🔥 

🔥线程的优点 🔥

🔥线程的缺点🔥 

🔥线程和进程之间的区别🔥 

🔥线程的用途 🔥

五、共勉 


一、前言

        将一份【代码成功编译】后,可以得到一个【可执行程序】,程序运行后,相关代码和数据被 【load】 到内存中,并且操作系统会生成对应数据结构(比如 PCB)对其进行管理及分配资源,准备工作做完之后,我们就可以得到一个运行中的程序,简称为 进程,对于操作系统来说,只有 进程 的概念是无法满足高效运行的需求的,因此需要一种执行粒度更细、调度成本更低的执行流,而这就是 线程

 Windows 中的线程

二、 什么是线程

【线程】是操作系统管理任务执行(CPU)的基本单位,它允许一个程序同时执行多个任务(进程中有很多执行流),从而实现并发(在同一时间段内处理多个任务)或并行(同时处理多个任务)。 

💧线程的引入💧 

想要真正的了解【线程】,就需要先了解【进程】因为线程是从进程中延申出来的,由于它们之间的概念十分的枯燥难以理解,我们用一个流程图,来给大家清楚的说明,线程和进程之间到底有那些千丝万缕的联系。

  • CPU与进程:CPU比作工厂,它一次只能处理一个车间(进程)的任务。如果一个车间正在使用电力,其他车间(进程)就必须等待。

  • 进程进程就好比是工厂中的车间,代表CPU正在执行的任务。在任一时刻,CPU只能运行一个进程,而其他进程则处于非运行状态。

  • 线程:线程比作车间里的工人。一个车间(进程)可以有很多工人(线程),他们协同工作以完成一个任务。一个进程可以包含多个线程。

  • 共享内存空间:车间的空间是工人们共享的,这象征一个进程的内存空间是共享的,每个线程都可以使用这些共享内存。

  • 互斥锁(Mutex:为了防止多个线程同时读写某一块内存区域,可以使用互斥锁。这就像是一个房间里面有人的时候,其他人就不能进去,必须在门口排队等待。

  • 资源限制有些房间(内存区域或资源)最多只能容纳一个人,这代表某些资源一次只能被一个线程使用。

 看完这幅图和解析,我相信大家已经能够对 进程和线程有了一个基本的认识,下面我们再来深度的解析,线程

💧线程的基本概念 💧

教材观点】

  1. 【线程】就是【进程】一个执行分支、执行粒度比进程更细、调度成本更低
  2. 线程就是进程内部的一个执行流

【内核观点】 

  • 【进程】承担系统资源分配的基本实体,而 【线程】是 CPU 运行的基本单位

💧线程的理解 💧 

【线程】是对以往【进程】概念的补充完善,正确理解线程概念是一件十分重要的事,理解 线程 之前需要先简单回顾一下 进程】

  • 程序运行后,相关的代码和数据会被 load 到内存中,然后操作系统为其创建对应的 PCB 数据结构、生成虚拟地址空间、分配对应的资源,并通过页表建立映射关系

详见:《Linux【进程地址空间】》 

 进程之间是相互独立

  • 即使是 父子进程,他们也有各自的 虚拟地址空间、映射关系、代码和数据(可能共享部分数据,出现修改行为时引发 写时拷贝机制) 
  • 如果我们想要创建 其他进程 执行任务,那么 虚拟地址空间、映射关系、代码和数据 这几样东西是必不可少的,想象一下:如果只有进程的概念,并且同时存在几百个进程,那么操作系统调度就会变得十分臃肿 
  • 操作系统在调度进程时,需要频繁保存上下文数据、创建的虚拟地址空间及建立映射关系

线程的出现

  • 为了避免这种繁琐的操作,引入了 【线程】 的概念,所谓 【线程】 就是:额外创建一个 task_struct 结构,该 task_struct 同样指向当前的虚拟地址空间,并且不需要建立映射关系及加载代码和数据,如此一来,操作系统只需要 针对一个 task_struct 结构即可完成调度,成本非常低

 为什么【切换进程】比 【切换线程开销大得多?

  • 在 CPU 内部包括:运算器、控制器、寄存器、MMU、硬件级缓存(cache,其中 硬件级缓存 cache 又称为 高速缓存,遵循计算机设计的基本原则:局部性原理,会预先加载 部分用户可能访问的数据 以提高效率。
  • 如果【切换进程】,会导致 高速缓存 中的数据无法使用(进程具有独立性),重新开始 预加载,这是非常浪费时间的(对于 CPU 来说)。
  • 但【切换线程】就不一样了,因此线程从属于进程,切换线程时,所需要的数据的不会发生改变,这就意味值 高数缓存 中的数据可以继续使用,并且可以接着 预加载 下一波数据

进程(process的 task_struct 称为 PCB线程(thread的 task_struct 则称为 TCB

  • 从今天开始,无论是 【进程 还是 【线程,都可以称为 执行流线程 从属于 进程当进程中只有一个线程时,我们可以粗粒度的称当前进程为一个单独的执行流;当进程中有多个线程时,则称当前进程为多执行流,其中每一个执行流就是一个个的线程 

总结:执行流的调度由操作系统负责,CPU 只负责根据 task_struct 结构进行计算 

  • 若下一个待调度的执行流为一个单独的进程,操作系统仍需创建 PCB 及 虚拟地址空间、建立映射关系、加载代码和数据
  • 但如果下一个待调度的执行流为一个线程,操作系统只需要创建一个 TCB,并将其指向已有的虚拟地址空间即可

现在面临着一个很关键的问题:进程和线程究竟是什么关系? 


💧进程与线程的关系💧

进程】是 承担系统资源分配的实体,比如 程序运行必备的:虚拟地址空间、页表映射关系、相关数据和代码 这些都是存储在 进程 中的,也就是我们历史学习中 进程 的基本概念 

线程】是 CPU 运行的基本单位,程序运行时,CPU 只认 task_struct 结构,并不关心你是 【线程】 还是 【进程】,不过,线程 包含于 进程 中,一个 进程 可以只有一个 线程,也可以有很多 线程,当只有一个 线程 时,通常将其称为 进程,但对于 CPU 来说,这个 进程 本质上仍然是 线程;因为 CPU 只认 task_struct 结构,并且 PCB 与 TCB 都属于 task_strcut,所以才说 线程是 CPU 运行的基本单位

总结:

  • 进程】是由操作系统将程序运行所需地址空间、映射关系、代码和数据打包后的资源包
  • 线程/轻量级进程/执行流 】则是利用资源完成任务的基本单位

线程包含于进程中,进程本身也是一个线程

我们之前学习的进程概念是不完整的,引入线程之后,可以对进程有一个更加全面的认识

  • 通常将程序启动,比如 main 函数中的这个线程称为 主线程,其他线程则称为 次线程 

实际上 进程 = PCB + TCB + 虚拟地址空间 + 映射关系 + 代码和数据,这才是一个完整的概念

以后谈及进程时,就要想到 一批执行流+可支配的资源

【进程】与【线程】的概念并不冲突,而是相互成就 

  • Linux 中,认为 【PCB】 与 【TCB】 的共同点太多了,于是直接复用了 PCB 的设计思想和调度策略,在进行 【线程管理】 时,完全可以复用 【进程管理】 的解决方案(代码和结构),这可以大大减少系统调度时的开销,做到 小而美,因此 Linux 中实际是没有真正的 线程 概念的,有的只是复用 PCB 设计思想的 TCB
  •  在这种设计思想下,【线程】 注定不会过于庞大,因此 Linux 中的 线程 又可以称为 轻量级进程(LWP轻量级进程 足够简单,且 易于维护、效率更高、安全性更强,可以使得 Linux 系统不间断的运行程序,不会轻易 崩溃

在Linux系统中,所有的执行流都被称为轻量级进程(Lightweight Process,LWP),实际上就是操作系统概念中的线程。在Linux中,线程和进程的区别并不是很明显,因为Linux将线程实现为与进程相似的实体,即轻量级进程。 

  • 在Linux中,每个【轻量级进程】(线程)都对应一个task_struct结构体,操作系统通过调度算法选择下一个要执行的轻量级进程,而不关心这个task_struct属于哪个进程,或者是属于一个进程的其中一个线程。
  • 因此,在Linux中,CPU调度的实际执行单元是轻量级进程(线程),而不是进程。每个轻量级进程都有自己的执行流,可以独立执行代码,拥有独立的栈空间和寄存器状态。多个轻量级进程可以共享一个进程的资源,实现并发执行。

💧程序如何划分(重拾页表、见一下LWP)💧 

操作系统进行内存管理的基本单位是【4KB

内存里都是以【4kb】大小分的一个一个内存块——空间

可执行程序也是以【4kb】进行分——内容

现在我们再来重新看待页表: 

  • 后12位叫做叶内偏移
  • 同时读取时还要结合数据类型的大小

总结:多个执行流即不同的线程执行不同的代码,获得各自的数据,本质就是让不同的线程各自看到不同的页表。

三、简单的使用线程

如何验证 Linux 中的【线程】呢? 简单使用一下就好了

接下来简单使用一下 pthread 线程原生库中的线程相关函数(只是简单使用,不涉及其他操作)

  • 给不同的线程分配不同的区域,本质就是给让不同的线程,各自看到全部页表的子集 
#include <iostream>
#include <thread>
#include <unistd.h>
#include <sys/types.h>using namespace std;// 线程分支
void *test(void *arg)
{while (true){// 在线程中打印进程PIDstd::cout << "I am new thread, pid: " << getpid() << std::endl;sleep(1);}
}int main()
{// 线程idpthread_t tid;pthread_create(&tid, nullptr, test, nullptr);  //创建一个新线程while (true){// 打印主线程的 进程PIDstd::cout << "I am main thread, pid: " << getpid() << std::endl; sleep(1);}return 0;
}
  • 函数编译完成,会出现两条分支,一条是主线程,一条之分支线程,我们需要观察吗,这两个线程是否在同一个进程内,这两个线程会有区别吗?

  • 编译程序时,需要带上 -lpthread 指明使用 线程原生库
  • 结果:主线程+一个次线程同时在运行

 使用指令查看当前系统中正在运行的 线程 信息

while :; do ps -aL | head -1 && ps -aL | grep thread ; echo "-----------------------------------"; sleep 1 ; done

可以看到此时有 两个个线程 

  • 细节1:两个个线程的 PID 都是 4071708
  • 细节2:个线程的 LWP 各不相同
  • 细节3:第一个线程的 PID 和 LWP 是一样的

其中,第一个线程就是 主线程,也就是我们之前一直很熟悉的 进程,因为它的 PID 和 LWP 是一样的,所以只需要关心 PID 也行 

操作系统如何判断调度时,是切换为 线程 还是切换为 进程 ? 

  • 将待切换的执行流 PID 与当前执行流的 PID 进行比对,如果相同,说明接下来要切换的是 线程,否则切换的就是 进程
  • 操作系统只需要找到 LWP 与 PID 相同的线程,即可轻松锁定主线程

线程是进程的一部分,给其中任何一个线程发送信号,都会影响到其他线程,进而影响到整个进程 


四、线程小结 

🔥再谈线程🔥 

Linux 中没有 真线程,有的只是复刻 进程 代码和管理逻辑的 轻量级线程(LWP 

线程 有以下概念: 

  • 在一个程序中的一个执行路线就叫做 线程(Thread),或者说 线程 是一个进程内部的控制程序
  • 每一个进程都至少包含一个 主线程
  • 线程 在进程内部执行,本质上仍然是在进程地址空间内运行
  • Linux 系统中,CPU 看到的 线程 TCB 比传统的 进程 PCB 更加轻量化
  • 透过进程地址空间,可以看到进程的大部分资源,将资源合理分配给每个执行流,就形成了 线程执行流

🔥线程的优点 🔥

 线程 最大的优点就是 轻巧、灵活,更容易进行调度

  • 创建一个线程的代价比创建一个进程的代价要小得多
  • 调度线程比调度进程要容易得多
  • 线程占用的系统资源远小于进程
  • 可以充分利用多处理器的并行数量(进程也可以)
  • 在等待慢速 IO 操作时,程序可以执行其他任务(比如看剧软件中的 “边下边看” 功能)
  • 对于计算密集型应用,可以将计算分解到多个线程中实现(比如 压缩/解压 时涉及大量计算)
  • 对于 IO密集型应用,为了提高性能,将 IO操作重叠,线程可以同时等待资源,进行 高效IO(比如 文件/网络 的大量 IO 需要,可以通过 多路转接 技术,提高效率)

线程 的合理使用可以提高效率,但 线程 不是越多越好,而是 合适 最好,让每一个线程都能参与到计算中 

🔥线程的缺点🔥 

线程 也是有缺点的: 

  • 性能损失,当 线程 数量过多时,频繁的 线程 调度所造成的消耗会导致 计算密集型应用 无法专心计算,从而造成性能损失 
  • 健壮性降低,在一个多线程程序里,因时间分配上的细微偏差或者因共享了不该共享的变量而造成不良影响的可能性是很大的,换句话说线程之间是缺乏保护的
  • 缺乏访问控制,进程是访问控制的基本粒度,在一个线程中调用某些OS函数会对整个进程造成影响 

 🔥线程和进程之间的区别🔥 

 虽然进程和线程之间很相似,但是它们之间还是存在着一些细小的区别

  • 进程:是操作系统进行资源分配和调度的一个独立单位,是应用程序运行的实例。每个进程都有自己的独立内存空间。
  • 线程:是进程中的执行单元,多个线程共享同一进程的内存空间和资源,但每个线程有自己的栈、程序计数器等。线程是CPU调度的基本单位

内存空间:

  • 进程:每个进程都有自己独立的内存空间,包括代码段、数据段、堆和栈。进程之间的内存是隔离的,不能直接访问对方的内存空间。
  • 线程:线程共享进程的内存空间,因此可以直接访问同一进程中的其他线程的数据,但这也带来了同步和并发控制的复杂性。

资源开销 

  • 进程:创建和切换进程的开销较大,因为涉及到完整的内存空间、资源的分配与回收。
  • 线程:线程创建和切换的开销相对较小,因为线程共享进程的资源和内存,切换时不需要进行完整的资源分配和回收。

通信方式 

  • 进程:进程间通信(IPC)需要通过操作系统提供的机制,如管道、消息队列、共享内存、信号量等,通信相对复杂且效率较低。
  • 线程:线程之间可以通过共享内存直接通信,通信效率较高,但需要小心处理同步问题,以避免竞态条件和死锁。

 并发性

  • 进程:由于进程是独立的单元,一个进程的崩溃通常不会影响其他进程。但进程间的并发性较低。
  • 线程:线程之间的并发性较高,可以在同一进程内并行执行任务。然而,一个线程的崩溃可能导致整个进程的崩溃。

进程与线程的一个简陋模型用图表示的话,是这样的: 


🔥线程的用途 🔥

 合理的使用 多线程,可以提高 CPU 计算密集型程序的效率

  • 进程:适合用于多任务、多用户的独立应用,如操作系统中的服务程序、独立的应用程序等。
  • 线程:适合用于需要并行执行共享大量数据的任务,如服务器的多线程处理、实时图像处理等。

五、共勉 

 以下就是我对【Linux系统编程】线程的深度解析 的理解,如果有不懂和发现问题的小伙伴,请在评论区说出来哦,同时我还会继续更新【Linux系统编程】请持续关注我哦!!!   

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

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

相关文章

基于springboot养老院管理系统pf

TOC springboot332基于springboot养老院管理系统pf 第1章 绪论 1.1选题动因 当前的网络技术&#xff0c;软件技术等都具备成熟的理论基础&#xff0c;市场上也出现各种技术开发的软件&#xff0c;这些软件都被用于各个领域&#xff0c;包括生活和工作的领域。随着电脑和笔记…

Python实战项目:天气数据爬取+数据可视化(完整代码)

一、选题的背景 随着人们对天气的关注逐渐增加&#xff0c;天气预报数据的获取与可视化成为了当今的热门话题&#xff0c;天气预报我们每天都会关注&#xff0c;天气情况会影响到我们日常的增减衣物、出行安排等。每天的气温、相对湿度、降水量以及风向风速是关注的焦点。通过…

实战OpenCV之图像显示

基础入门 OpenCV提供的功能非常多&#xff0c;图像显示是最基础也是最直观的一部分。它让我们能够直观地看到算法处理后的效果&#xff0c;对于调试和验证都至关重要。在OpenCV中&#xff0c;图像显示主要依赖于以下四个关键的数据结构和函数。 1、Mat类。这是OpenCV中最基本的…

LeetCode - LCR 146- 螺旋遍历二维数组

LCR 146题 题目描述&#xff1a; 给定一个二维数组 array&#xff0c;请返回「螺旋遍历」该数组的结果。 螺旋遍历&#xff1a;从左上角开始&#xff0c;按照 向右、向下、向左、向上 的顺序 依次 提取元素&#xff0c;然后再进入内部一层重复相同的步骤&#xff0c;直到提取完…

MySQL数据库入门,pycharm连接数据库—详细讲解

一.安装MySQL 1.常用MySQL5.7&#xff0c;首先安装MySQL&#xff0c; &#xff08;一&#xff09; &#xff08;二&#xff09; &#xff08;三&#xff09; &#xff08;四&#xff09; &#xff08;五&#xff09; 2.配置环境变量 打开MySQL安装路径&#xff0c;在其中找到…

ArcGis在线地图插件Maponline(好用版)

ArcGis加载插件&#xff0c;可在线浏览谷歌地图、天地图、高德地图、必应地图等多种&#xff0c;包含街道、影像、标注地图等信息&#xff08;谷歌地图需自备上网手段&#xff09;&#xff0c;免费注册账号即可使用&#xff0c;可加载无水印底图。 与大地2000坐标无需配准直接使…

洛杉物理服务器怎么样?

洛杉矶作为美国科技和互联网的重要中心&#xff0c;物理服务器的质量通常非常高&#xff0c;可以提供卓越的性能、强大的安全性、多样的配置选项和专业的服务支持。以下是对洛杉物理服务器的详细介绍。 1. 优质的性能 稳定的网络连接&#xff1a;洛杉矶物理服务器位于先进的数据…

day32+学习记录

一.算法练习 509.斐波那契数 斐波那契数 &#xff08;通常用 F(n) 表示&#xff09;形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始&#xff0c;后面的每一项数字都是前面两项数字的和。也就是&#xff1a; F(0) 0&#xff0c;F(1) 1 F(n) F(n - 1) F(n - 2)&#xf…

一键运行RocketMQ5.3和Dashboard

一键运行RocketMQ5.3和Dashboard 目录 一键运行RocketMQ5.3和Dashboard通过Docker Compose 来一键启动运行的容器包括docker-compose.yml文件运行命令启动本地效果查看 参考信息 通过Docker Compose 来一键启动 运行的容器包括 NameServerBrokerProxyDashBoard docker-compo…

关于Qt的系统总结

查看详情http://100bcw.com/qt6.htm 编译环境与开发流程 开发QT有两种IDE可以使用,一种是使用 VS + Qt 的插件,另一种就是使用QtCreator工具。前一种是微软的工具,用的都比较多容易上手,缺点是信号槽的支持不太好,需要手写,不能自动生成,另外可能有中文编码的问题。后一…

c语言 图片.bmp读写示例

1 图片.bmp数据结构 BMP&#xff08;Bitmap&#xff09;文件格式是一种简单的位图图像格式&#xff0c;其数据结构分为几个主要部分&#xff1a;文件头、信息头、调色板&#xff08;可选&#xff09;和像素数据。下面是各部分的详细说明。 文件头&#xff08;File Header&…

东晟时尚服饰文化传承与发展研发中心成立

近期&#xff0c;东晟时尚创新科技&#xff08;北京&#xff09;有限公司宣布成立东晟时尚服饰文化传承与发展研发中心&#xff0c;此举标志着公司在促进中国传统文化与现代时尚产业结合方面迈出了关键步伐。 作为一家在时尚科技推广和设计研发应用服务领域具有战略眼光的企业&…

【问题记录+总结】VS Code Tex Live 2024 Latex Workshop Springer模板----更新ing

目录 Summary 道阻且长 少即是多 兵马未动粮草先行 没有万能 和一劳永逸 具体问题具体分析 心态 Detail 1、关于模板[官网] 2、settings.json 3、虫和杀虫剂 4、擦 换成Tex Studio都好了。。。 Summary 道阻且长 某中意期刊&#xff0c;只有Latex。之前只简单用过…

部署 K8s 图形化管理工具 Dashboard

文章目录 一、Dashboard 概述二、GitHub 地址三、Dashboard 部署安装1、选择兼容版本2、下载配置文件3、添加 Dashboard 的Service类型4、应用部署5、查看 kubernetes-dashboard 命名空间下资源状态6、创建访问账户7、授权8、获取账号token9、1.24 版本以后的需要创建一个Pod 四…

C++ 11相关新特性(lambda表达式与function包装器)

目录 lambda表达式 引入 lambda表达式介绍 lambda表达式捕捉列表的传递形式 lambda表达式的原理 包装器 包装器的基本使用 包装器与重载函数 包装器的使用 绑定 C 11 新特性 lambda表达式 引入 在C 98中&#xff0c;对于sort函数来说&#xff0c;如果需要根据不同的比较方式实现…

自闭症青年的行为特征有哪些

自闭症&#xff0c;又称孤独症&#xff0c;是一种神经发育障碍&#xff0c;它不仅影响儿童的成长&#xff0c;也会在青年时期展现出一系列独特的行为特征。了解这些特征对于更好地支持和帮助自闭症青年融入社会至关重要。 社交互动方面的困难是自闭症青年较为显著的特征之一。他…

Kubectl 常用命令汇总大全

kubectl 是 Kubernetes 自带的客户端&#xff0c;可以用它来直接操作 Kubernetes 集群。 从用户角度来说&#xff0c;kubectl 就是控制 Kubernetes 的驾驶舱&#xff0c;它允许你执行所有可能的 Kubernetes 操作&#xff1b;从技术角度来看&#xff0c;kubectl 就是 Kubernetes…

openEuler系统安装Visual Studio Code

openEuler系统安装Visual Studio Code 背景安装密钥和存储库更新包缓存并使用dnf安装包Fedora 22及以上版本旧版本使用yum 安装过程截图安装成功看桌面效果 背景 openEuler(openEuler-24.03-LTS)安装了麒麟UKUI桌面但是没有麒麟软件商店想安装Visual Studio Code 安装密钥和…

专业剪辑新选择!2024年TOP榜达芬奇剪辑软件VS三大劲敌的较量

到了2024年&#xff0c;科技飞快地进步&#xff0c;视频剪辑这一块儿也变了不少。老的剪辑方法一直被刷新&#xff0c;新的软件一个接一个冒出来&#xff0c;像达芬奇剪辑软件这样的&#xff0c;都成了拍视频的人的好伙伴。咱们今天就来聊聊这几款软件有啥神奇的&#xff0c;比…

安全基础学习-RC4加密算法

这里仅仅记录一些基础的概念。后期有需求进一步扩展。 RC4 是一种对称流加密算法&#xff0c;由罗恩里维斯特&#xff08;Ron Rivest&#xff09;于1987年设计。RC4 的设计目的是提供一种简单且高效的加密方法。尽管 RC4 曾经广泛使用&#xff0c;但它的安全性在现代已受到质疑…