深圳网站建设找哪,做单页网站容易排名吗,全球采购网登录,闽侯福州网站建设文章目录 1.Linux中线程该如何理解2.重新定义线程 和 进程3.重谈地址空间 --- 第四讲4.Linux线程周边的概念 线程:是进程内的一个执行分支。线程的执行粒度,要比进程要细 很多教材喜欢这么说#xff0c;这只是一个线程的特征之一#xff0c;来解释线程。 1.Linux中线程该如何… 文章目录 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有寄存器保存当前调度进程的PCBPCB找到地址空间就找到了而地址空间其实也有字段找到它的页表 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 会从左往右按照101012被拆成 0000000000 0000010000 000000000101 1010,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线程周边的概念