线程...

news2025/2/26 22:52:50

文章目录

  • 1.Linux中线程该如何理解
  • 2.重新定义线程 和 进程
  • 3.重谈地址空间 --- 第四讲
  • 4.Linux线程周边的概念

线程:是进程内的一个执行分支。线程的执行粒度,要比进程要细
很多教材喜欢这么说,这只是一个线程的特征之一,来解释线程。

1.Linux中线程该如何理解

地址空间是进程的资源窗口!
你的进程想访问用户空间和访问OS都必须通过地址空间去查看,加上页表转化去物理内存中去找
在这里插入图片描述

我们以前创建子进程,父子进程在数据结构上相互独立,需要给子进程开辟新的pcb,地址空间,页表,虽然大部分都是从父进程来的。
如果我今天再创建一个“进程” 不再给它创建新的地址空间,新的页表,我只创建pcb,让其指向父进程的地址空间,也指向父进程的页表(我们不管)
他们两个pcb把代码区分一部分,全局数据区分一部分,堆区分一部分给这个新的“进程”,或者两个Pcb直接共享某个区域
此时新的子进程就在父进程的地址空间内运行,同时把页表中对应分出来区域的映射给新的子进程就可以了
既然能创建一个,就能创建多个,只创建pcb,把一个进程的地址空间分成若干份分给子进程部分代码。
此时线程的执行粒度,要比进程更细,为什么这么说?
以前主进程执行全部代码,现在只需要执行全部代码一部分。
它只执行其中一部分,所以把它称为进程内的一个执行分支。
为了区分和fork创建子进程的区别,把这种形式的进程起个名字叫做 线程

Linux实现方案 – 结论

1.在Linux中,线程在进程“内部”执行,更详细的说是线程在进程的地址空间内运行(为什么? )
任何执行流要执行,都要有资源! 地址空间是进程的资源窗口
你进程或线程你要执行你要不要代码,没有代码和数据你就跑不起来,你要的话就得在地址空间内要。

2.在Linux中,线程的执行粒度要比进程要更细? 线程执行进程代码的一部分

站在CPU角度它知不知道哪个task_struct是进程,哪个是线程?或者他需不需要知道?
cpu不需要关心它执行的是进程还是线程,它只有调度执行流的概念
cpu要代码和数据你就给他,让他找到代码和数据执行就行了

2.重新定义线程 和 进程

什么叫做线程呢?我们给个定义
我们认为,线程操作系统调度的基本单位!
(我们以前可根本没说进程是OS基本调度单位,没说过。)

以前不都是拿着个进程调度来调度去,那什么叫进程呢?
所有的执行流都叫进程执行流,地址空间都叫做进程所占有的资源,页表和进程在物理内存中代码和数据,把这一整套称之为进程
重新理解进程? 内核观点: 进程是承担分配系统资源的基本实体
在这里插入图片描述

所以显而易见地址空间页表代码和数据都是要占资源的,那pcb执行流是资源吗?
是的
不要认为一个进程能被调度它就是进程的所有,它只是进程内部的一个对应的执行流资源被cpu执行了。
线程只是进程概念中的基本调度单元,所以进程和线程的关系是进程内部包含线程,因为进程是承担分配系统资源的基本实体,而你线程是我进程内部的执行流资源。

以前给的进程概念:进程= 内核数据结构(task_struct) +代码和数据— v1
当然也是对的,指的是所有的内核数据结构,所有的PCB

创建进程OS会给他分配很多资源,如果你要创建线程,在进程内部创建pcb,然后把进程的资源分出一部分给你线程你去调度吧,你去执行吧。

可是如何理解我们以前的进程???
在这里插入图片描述

操作系统以进程为单位,给我们分配资源,我们当前的进程内部,只不过当前进程只有一个执行流 !

复用进程数据结构和管理算法
struct task_strut ----模拟线程
如果你的资源PCB只有一个那你就是进程,如果内部有多个PCB就是线程

甚至linux中我不区分PCB是进程还是线程,我都把他叫执行流,承担分配系统资源的基本实体才是进程


(那么如果我们真正的一个进程内部要有对应的线程,所以进程和线程它对应的比例一定是1:n的至少是1:1,也就是一个进程里面应该有多个线程
所以你这个线程执行的时候,那么当前的状态是什么?那么你这个线程当前执行到什么位置了?当前需要访问哪些资源?即将访问哪些资源?你这个线程是属于哪个进程的?你这个线程呢在调度的时候啊,那么什么时候被切换了?需要被切换吗?时间片有没有到等等等等啊,
第二线程可不是一创建就退出,一创建就完成,是创建才是开始,操作系统要能够调度这个线程,那要运行这个线程,切换这个线程,所以线程又多,比进程还多,你还要来对他做调度,一个问题,操作系统要不要管理线程?
那我当然要管理啊,你不管理我,我这个线程我应该属于哪个进程?我的地址空间在哪里?我的代码在哪里?我调度到哪里了,我状态是什么?
必须得管怎么管理,先描述再组织
先描述再组织,你想一想吧,曾经光光这么多的PCB就把你搞得头昏脑胀的,那么再来给你搞一大堆的tcb啊,你先描述tcb再组织,你组织一下试试,,这个线程出问题还要影响整个进程,等那个复杂的关系维护会特别特别特别特别特别复杂
Windows操作系统他就这么干了,他就给线程创建的tcp,然后再把进程和线程之间还有关联起来
那么我们Linux呢,他们是这么认为的你这个线程不也被调度吗?你线程要的代码和进程的代码,无非线程的代码少了一点儿,你也要切换,也要调度,无非就是线程的资源少一点嘛,好,那么Linux的设计者来说,我们当然要遵守人家的设计哲学,对线程要管理,先描述,再组织,可是谁规定描述必须得用新的方法来描述,谁规定描述都必须得用组织都必须得用新的,组织方式用新的来组织。
其实你的进程和线程高度类似可以复用tast_struct结构体来模拟线程,那么进程我们已经描述了,他们都有状态,有优先级,要有自己的上下文要被切换。)


我们把LInux当中的执行流,叫做轻量级进程
因为 执行流 <= 进程 你执行流要是进程 那就相等 ,执行流要是线程那就是粒度<进程

3.重谈地址空间 — 第四讲

问题:如何理解把资源分配给每个线程(执行流)?

CPU有寄存器保存当前调度进程的PCB,PCB找到地址空间就找到了,而地址空间其实也有字段找到它的页表
CR3寄存器能找到页表
物理内存分成了一个一个页框,每个页框4KB 按照字节换算 是 2^12 byte
在这里插入图片描述
下面重点谈页表
虚拟地址是如何转换到物理地址的?? ?

从物理内存页框内容当中读取到CPU的地址是虚拟地址,然后在CPU内部做转化找到物理地址
3位虚拟地址为例
虚 拟地址是多少位的? 32位
如何理解页表呢?
第一 32位虚拟地址 不是一个整体 而是转化成了 10 + 10 + 12 = 32
第二 页表也不是一整块的,如果他是一整块,每一个行中有虚拟地址,物理地址,权限位假设有10字节,页表被写满,有2^32个地址,也就是2 ^32行,再乘以10结果是字节进行换算大概是40G
这样整个物理内存放不下这一张页表,更别提所有进程都有页表了
所以页表不可能是我们以前画的一张大表
在这里插入图片描述
页表是拆成了两级的
第一级页表有1024个条目,二级页表也有1024个条目
你将来在CPU寻址读到的虚拟地址有32位 ,假如是 0000 0000 0000 0001 0000 0000 0000 0101
会从左往右按照10+10+12被拆成 0000000000 0000010000 000000000101
10,10,12每个区域都有自己的十进制数,范围:从全0到全1
在这里插入图片描述

用第一个十个比特位转化成十进制数 充当第一级页表的数组下标。
一级页表存放的是二级页表对应的地址,接着找到二级页表,
拿着第二个十进制数索引二级页表中的下标,
二级页表中保存的是物理内存中页框的起始地址(低地址),所以就能找到物理内存中的页框了。

一级页表一般叫 页目录
页目录里面的内容 叫 页目录表项

二级页表里面 的内容 叫 页表表项

其实只需要通过虚拟地址前20位查一级查二级页表其实已经找到对应的页框了。
接下来还有剩下的12位范围[0,2^12-1]一共2 ^12个,刚好是页框的大小,12位相当于你要访问物理内存在页框中的偏移量,用页框地址 + 虚拟地址的最后12位 = 物理地址
在这里插入图片描述
下面我们来算算账

先算一个页表有多大?
二级页表一行中保存了页框的起始地址 ,按4字节算,不算二级页表中的权限位
一共有1024行,也就是 4 x 1024 = 4096byte = 4kb
则一个页表是可以放进一个页框里面的

一级页表中一共有 1024个二级页表,所以所有页表大小: 1024 x 4kb = 4096 kb = 4MB
一级页表就一个4KB 没算进去
所以说这1024 个二级页表 4MB 和之前40G的大表相比 少了很多

一个进程会把整个地址空间全部用完吗?一部分地址空间根本不需要给每个进程都维护的,内核级页表只需要维护一份就行了。
每个进程只需要维护0-3G

每个进程不一定把整个地址空间全用完,二级页表不一定全部存在。
二级页表在大部分情况下都是不全的!
这样算就比4MB还小,即便是进程把页表用全了,还有页面置换算法来维护
所以极端情况是4MB,但是大部分情况进程只会用到其中很少一部分,所以进程的页表就大大减少了

页表不会很大架不住进程个数多,所以我们说创建一个进程依旧是一个很 “重” 的工作,所以才有线程存在的意义和背景。


二级页表保存的页框地址个数 和 物理内存的页框个数对着呢吗?
对着呢
这是物理内存一共有1048576 = 2 ^ 20个页框,从下往上你就算吧
在这里插入图片描述
一共有1024个二级页表,每个二级页表保存了1024个地址,也就是1024 X 1024 = 1048576 个地址


虚拟地址整个10 10 12划分 ,它为什么这么划分呢? 这个12为什么要有呢?
答:
根本原因就在于配合内存管理
今天页框大小是4KB,有的OS把页框干成4MB,最终页表还会更小
因为物理内存分的页框个数少了,要保存的地址也就少了,页表也就小了

它为什么是4KB呢,因为它和12是相对应的!


所以要访问一个虚拟地址时,OS怎么知道这个虚拟地址有没有加载到内存呢?
答:
1.可能你查一级页表时二级页表不存在,那就没有被加载到内存,所以缺页中断

2.可能你访问二级页表里和对应的页框并没有建立映射关系,此时也没有加载到内存,二级页表里面有标记位确认映射关系有没有。


因为二级页表只能索引到页框,所以内存管理的基本单位是4KB


你现在虚拟转物理只能找到一个字节的地址,那我们的int, double
float,各种自定义类型 怎么说?
在这里插入图片描述

int a = 10;
整形有4个字节,&a只拿到了一个地址,用它的低地址做代表
C/C++中任何变量只有一个地址就是内存中开辟的多字节起始地址
找到这个起始地址,根据类型连续读取多个字节就把数据读取上来了。

计算机他怎么知道我要读取几字节?
类型被CPU转化成偏移量,类型是给cpu看的,
汇编中内置了命令读取1,2字节的命令,dword ,word字
CPU和内存连着呢(冯诺依曼),软件定位到了内存中起始物理地址,CPU拷贝时它就知道拷贝几字节了

你说的是内置类型,我要是结构体,类呢?
结构体,类不都是由内置类型的集合描述的。
就算结构体很大,CPU很小,我就能读多少读多少

C/C++中任何变量只有一个地址就是内存中开辟的多字节起始地址
说白了我们访问任何一个变量都叫做起始地址+类型 本质就是 起始地址 + 偏移量


所以最终一句话
虚拟地址到物理地址的转化 它只需要查10 10 12 找到页框再在页框内索引
至此就完成了虚拟到物理的转化

CPU内部的CR3寄存器直接指向一级页表,任何进程二级页表可以没有或残缺,但任何进程必须要有一级页表存在!后面随着运行过程页表缺页中断会被填充越来越完善。

当物理地址访问时,物理地址不存在 or 越界了
CPU内部还有一个寄存器叫做CR2 保存 引起缺页中断 or 异常的虚拟地址
相当于你进行访问二级页表,而二级页表不存在,不存在你说要缺页中断 把页面调换进来在内存里申请构建映射关系,你把这些做完了我怎么知道上次访问的虚拟地址是谁呢?
当它把这个工作做完就会把CR2保存的虚拟地址拿出来重新访问。


下面在回答一下最开始的问题
如何理解资源分配?
上面所讲的这个线程,它所对应的所有的资源分配全部都是通过地址空间来的,而你所有的代码和数据都是通过我们的地址空间页表然后映射过来的,
那么现在我的问题,我们线程分配资源在地址空间角度
线程目前分配资源 , 本质就是分配地址空间范围 ,页表你就别动了。
页表,物理内存都给我分配好了,一个线程它 要分配资源,目前站在地址空间角度,因为地址空间本身就是资源窗口,线程分配资源本质就是把地址空间划分一部分,就是你用你的,我用我的,比如说把代码分成几部分给几个线程,凡是不划分的比如堆区,全局数据区所有线程全部共享
所以线程资源分配本质就是空间范围的分配,因为所有的线程也共同属于同一个进程,大家使用同一个页表映射,查同一个页表,换句话说,
你把哪一部分资源给这个线程,其实就是把对应代码范围给它就可以了

那这个划分工作难不难呢?
以代码为例,全局数据不需要划分,就是要被所有线程共享
剩下的大部分区域线程都能共享
最重要的是代码,你怎么让每一个线程执行不同的代码?
代码有地址吗?
有,所以才有函数指针的概念。代码的地址也是虚拟地址
我们可以定义上10个函数,每个函数地址都不一样,所以把一个函数交给一个线程运行它天然就在代码层面上已经做好了地址空间划分上的分开。
10个函数每一个函数内部所有地址都是互相独立的,所以把每个函数给每个线程去跑,天然在函数上就划分好了。这就叫线程之间代码就分离了
你做了什么呢?
你只需要在代码中编译,编译好让所有线程执行不同函数就行了
所以线程就跑起来了

4.Linux线程周边的概念

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

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

相关文章

力扣 --- 最后一个单词的长度

题目描述&#xff1a; 给你一个字符串 s&#xff0c;由若干单词组成&#xff0c;单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。 单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。 示例 1&#xff1a; 输入&#xff1a;s "Hello World&…

GEE:Sobel算子卷积和Roberts算子卷积对比

作者:CSDN @ _养乐多_ 本文介绍了Sobel算子卷积和Roberts算子卷积操作的代码,并进行了图像对比,可以观察到两个算子的细微差异。 文章目录 一、Sobel算子和Roberts算子对比二、完整代码三、代码链接一、Sobel算子和Roberts算子对比 详细介绍介绍参考《遥感数字图像处理教程…

计算机导论——第39章 文件和目录

除了虚拟化CPU和内存&#xff0c;另外一个是持久存储&#xff0c;永久存储信息。持久存储设备与内存不同&#xff0c;内存在断电时内容会丢失&#xff0c;而持久存储设备会保持这些数据不变。 1. 文件和目录 文件就是一个线性字节数组&#xff0c;每个字节都可以读取或者写入…

DBS note7 (end):DB Design

目录 一、前言 二、引言 三、Entity-Relationship Models&#xff08;实体-关系模型&#xff09; 1、关系约束 三、函数依赖和正则化 1、BCNF分解 2、无损分解 3、依赖关系保留分解 一、前言 略读过一遍CS186&#xff0c;对于CS186来说&#xff0c;绝对不止这 7 篇笔记…

windows 你的电脑不能投影到其他屏幕,请尝试重新安装驱动程序

注意 千万不要去下载什么驱动精灵&#xff0c;太垃圾不好用还一堆附带的软件。按以下步骤进行解决&#xff1a; 解决方法 可能是显卡驱动的问题&#xff0c;我的笔记本按照如下步骤重启一下驱动后解决了&#xff0c;步骤如下: 右键点击桌面的开始菜单&#xff0c;选择”设备…

算法通关村第十六关-白银挑战滑动窗口经典题目

大家好我是苏麟 , 今天带来滑动窗口经典的一些题目 . 我们继续来研究一些热门的、高频的滑动窗口问题 大纲 最长子串专题无重复字符的最长子串 长度最小的子数组盛最多水的容器 最长子串专题 无重复字符的最长子串 描述 : 给定一个字符串 s &#xff0c;请你找出其中不含有重…

React如何像Vue一样将css和js写在同一文件

如果想在React中想要像Vue一样把css和js写到一个文件中&#xff0c;可以使用CSS-in-JS。 使用CSS-in-JS 下载 npm i styled-components使用 就像写scss一样&#xff0c;不过需要声明元素的类型 基本语法及展示如下&#xff0c; import styled from "styled-component…

React使报错不再白屏

如果代码中出现问题导致报错&#xff0c;通常会使页面报错&#xff0c;导致白屏 function Head() {// 此时模拟报错导致的白屏return <div>Head --- {content}</div> } export default () > {return (<><div>下面是标题</div><Head />…

Swing程序设计(7)JPane面板,滑动面板

文章目录 前言一、JPane面板&#xff0c;滑动面板是什么&#xff1f;二、实操展示 1.JPane面板2.JScrollPane面板总结 前言 该篇博客介绍Java的Swing程序中JPane面板以及&#xff0c;滑动面板的使用。面板的使用&#xff0c;各个组件在不同的面板上被不同地摆放&#xff0c;让插…

MATLAB Simulink +STM32硬件在环 (HIL)实现例程测试

MATLAB Simulink STM32硬件在环 &#xff08;HIL&#xff09;实现例程测试 &#x1f4cd;相关篇《STM32CubeMxMATLAB Simulink点灯程序》✨本例程没有使用到STM32CubeMX来创建工程&#xff08;在Simulink 中不是选择的STM32xxxbased类型的&#xff09;。 &#x1f516;STM32xxx…

Github无法打开

文章目录 一、问题二、解决2.1、科学上网&#xff08;使用中&#xff09;2.2、使用代理&#xff08;不稳定&#xff09;2.3、修改hosts&#xff08;得更新&#xff09;2.3.1、找到hosts文件2.3.2、复制hosts文件2.3.3、添加记录2.3.4、替换原来的hosts文件2.3.5、成功访问Githu…

W2311294-万宾科技可燃气体监测仪怎么进行数据监测

万宾科技可燃气体监测仪怎么进行数据监测 燃气是现代城市之中重要的能源&#xff0c;它已经渗透到城市生活的方方面面&#xff0c;对燃气管网的管理也在考验着政府人员的工作能力。燃气管网的安全运行和城市的安全和人民的生活直接挂钩。为了及时掌握燃气管网的运行状态&#x…

2023年GopherChina大会-核心PPT资料下载

一、峰会简介 自 Go 语言诞生以来&#xff0c;中国便是其应用最早和最广的国家之一&#xff0c;根据 Jetbrains 在 2021 年初做的调查报告&#xff0c;总体来说目前大概有 110 万专业的开发者 选择 Go 作为其主要开发语言。就其全球分布而言, 居住在亚洲的开发者最多&#xff…

了解大模型 RAG (Retrieval-Augmented Generation):大模型外挂知识库 (检索增强技术)

本心、输入输出、结果 文章目录 了解大模型 RAG &#xff08;Retrieval-Augmented Generation&#xff09;&#xff1a;大模型外挂知识库 &#xff08;检索增强技术&#xff09;前言什么是检索增强技术 RAG &#xff08;Retrieval-Augmented Generation&#xff09;检索增强技术…

RocketMQ领域模型详解

1、主题&#xff08;Topic&#xff09; 1.1、定义​ 主题是 Apache RocketMQ 中消息传输和存储的顶层容器&#xff0c;用于标识同一类业务逻辑的消息。 主题的作用主要如下&#xff1a; 定义数据的分类隔离&#xff1a; 在 Apache RocketMQ 的方案设计中&#xff0c;建议将不同…

【STM32】STM32学习笔记-STM32简介(02)

00. 目录 文章目录 00. 目录01. STM32简介1.1 STM32是什么1.2 STM32应用领域1.3 STM32命名规则1.4 STM32选型 02. ARM简介2.1 ARM是什么2.2 ARM系列 03. STM32开发板3.1 MCU简介3.2 STM32开发板3.3 STM32硬件资源 04. STM32系统架构05. STM32引脚定义06. STM32启动配置07. STM3…

python爬虫AES魔改案例:某音乐素材下载网

声明&#xff1a; 该文章为学习使用&#xff0c;严禁用于商业用途和非法用途&#xff0c;违者后果自负&#xff0c;由此产生的一切后果均与作者无关 一、找出需要加密的参数 js运行 atob(‘aHR0cHM6Ly93d3cuYWlnZWkuY29tL3NvdW5kL2NsYXNzLw’) 拿到网址&#xff0c;F12打开调…

类 —— 多态、抽象类

多态 通常说的多态&#xff0c;是指发生在类之间的多态。即相同的代码&#xff0c;实现不同的功能。 函数重载 —— 静态多态/编译时多态。 类之间的多态 —— 动态多态/运行时多态。 前提 继承、虚函数、函数重写。 函数重写&#xff08;override&#xff09; 在子类中重…

正则表达式从放弃到入门(2):grep命令详解

正则表达式从放弃到入门&#xff08;2&#xff09;&#xff1a;grep命令详解 总结 本博文转载自 这是一篇”正则表达式”扫盲贴&#xff0c;如果你还不理解什么是正则表达式&#xff0c;看这篇文章就对了。 如果你是一个新手&#xff0c;请从头阅读这篇文章&#xff0c;如果你…

设计一门编程语言:你认为最重要的一定要有的特性会是哪些?

当我们站在软件工程师的角度来考虑设计一门编程语言时&#xff0c;我们需要关注那些能够提升代码质量、开发效率和程序可维护性的特性。 以下是我认为最重要的几个特性&#xff1a; 1、简洁而明确的语法&#xff1a;语法是程序员与编程语言交互的基础。简洁明了的语法可以降低…