ch4-8 进程,线程,cpu调度,进程同步(通信),死锁deadlock
- 进程
- 依次执行 一段程度在内存中可对应若干进程
- 进程可创建进程(父子进程,相关联,父进程有一个新任务让子去做) os大管家,管理实体,进程是个实体进程诞生的标志:分配了内存;诞生方式:父创,命令行,双击……
- 管理资源需要知道资源的信息--进程包含(os角度):234跟进程个体和运行相关;os把程序load到内存,load代码区和数据区
- PCB控制块,用于os管理和记录进程,与进程自身运行无关,优先级、使用多长时间等进程的属性--struct中若干属性成员。PCB有专门的数据结构。
- programcode(代码区)
- 动态存储区(堆栈)(数据区)
- 进程运行的现场或叫上下文:pc(根据cpu自动更新,不同cpu不同,有等长指令有不等长--关于指令集设计部分,取下一条指令;pc是特殊寄存器,放地址)和registercontent(cpu脑细胞那时刻的值,是在不断变化的)
- 进程消亡:(理想状态)回收资源;也可能资源释放不掉,os无法回收,bug,非合法方式编的程序。os:分配和回收资源。
- 在未引入线程时,可以说进程是执行体。相对程序只能静态储存,进程可以具有并发性。
- 进程的特征:进程是资源分配的基本单位--与线程的区别
- 协作进程:有直接间接关联
- 不可预知性
- state(本教材里挂起状态未提及),状态越多,对管理者来说更灵活复杂,工作量几何级增加:运行,阻塞,就绪--三个必有 进程自身和环境变化
- 进程状态迁移图(动态和牵连的)
- new后默认进入ready
- ready 其他各种资源都等到了,只差cpu时,进入该状态。 该状态下的进程队列,cpu一旦空闲则进行调度(不同os不同策略方式,但只能从就绪中调度scheduler dispatch让进程处于running状态)资源是有等级的。
- running:被cpu执行了,只有在就绪队列的进程下一状态才能执行(队列只有一个时无需选择)
- 中断(为什么要放弃cpu:时间片;或进程被中断,抢占式,在ready里有高优先级进程)--假设是死循环占了cpu,无吞吐量,为进程分配时间片--running状态之后时间片倒计时,为零时将cpu返回给系统,进程重新到ready排队,并且马上进行scheduler dispatch。需要等待其他io设备(io被其他占用)时,进程进入等待或叫被阻塞,并且马上进行scheduler dispatch。
- 进程等待不同资源时放到一个队列里等待或者根据资源不同放入不同队列等待。需要另一进程结果,某一资源,初始化io且须等待结果等等时进入等待。
- 进程调度(是一种算法),是cpu核心的一段代码。os一个模块,执行单元和装载一样?调度算法也用在等待队列获得资源变成就绪状态。即就绪到运行,等待到就绪都需要调度。
- PCB 一一对应 ,释放时该资源也释放。内存有系统区和用户区。PCB在系统区,由os创建维护修改。
- 可以把上下文(pc+registercontent)放在用户区,压在栈里,节省系统区资源。系统区资源只要机器开着一直在使用。占用越多,用户共享区越少。使得管理成本减少,不能因为管理而浪费资源。
- 优先级,时间片(cpu调度信息);内存信息--内存是变化的,使用也是变化的,需要记录进程内存的分配管理,使用者不同用户-系统级、用户级哪个用户等等信息。
https://www.douban.com/note/149709075/linux下sched.h源码文件分析
- 补充挂起:
现在大多数进程支持挂起。ready和waiting(逻辑资源或物理资源)有队列。
理解一:挂起是一种主动行为,因此恢复也应该要主动完成,而阻塞则是一种被动行为,是在等待事件或资源时任务的表现,你不知道他什么时候被阻塞(pend),也就不能确切 的知道他什么时候恢复阻塞。而且挂起队列在操作系统里可以看成一个,而阻塞队列则是不同的事件或资源(如信号量)就有自己的队列。
理解二:阻塞(pend)就是任务释放CPU,其他任务可以运行,一般在等待某种资源或信号量的时候出现。挂起(suspend)不释放CPU,如果任务优先级高就永远轮不到其他任务运行,一般挂起用于程序调试中的条件中断,当出现某个条件的情况下挂起,然后进行单步调试。
理解三:pend是task主动去等一个事件,或消息.suspend是直接悬挂task,以后这个task和你没任何关系,任何task间的通信或者同步都和这个suspended task没任何关系了,除非你resume task;
理解四:任务调度是操作系统来实现的,任务调度时,直接忽略挂起状态的任务,但是会顾及处于pend下的任务,当pend下的任务等待的资源就绪后,就可以转为ready了。ready只需要等待CPU时间,当然,任务调度也占用开销,但是不大,可以忽略。可以这样理解,只要是挂起状态,操作系统就不在管理这个任务了。
理解五:挂起是主动的,一般需要用挂起函数进行操作,若没有resume的动作,则此任务一直不会ready。而阻塞是因为资源被其他任务抢占而处于休眠态。两者的表现方式都是从就绪态里“清掉”,即对应标志位清零,只不过实现方式不一样。
挂起线程的意思就是你对主动对雇工说:“你睡觉去吧,用着你的时候我主动去叫你,然后接着干活”。
使线程睡眠的意思就是你主动对雇工说:“你睡觉去吧,某时某刻过来报到,然后接着干活”。
线程阻塞的意思就是,你突然发现,你的雇工不知道在什么时候没经过你允许,自己睡觉呢,但是你不能怪雇工,肯定你这个雇主没注意,本来你让雇工扫地,结果扫帚被偷了或被邻居家借去了,你又没让雇工继续干别的活,他就只好睡觉了。至于扫帚回来后,雇工会不会知道,会不会继续干活,你不用担心,雇工一旦发现扫帚回来了,他就会自己去干活的。因为雇工受过良好的培训。这个培训机构就是操作系统。
- 进程控制块(管理代价,系统区)+【user stack(过程调用,参数传递)+代码区数据区+shared addressspace】(用户区) 在虚存中进程映像,真实情况下不是占了内存的一整块(内存管理)。
分配,跟踪(对内存的需要是动态的,系统根据进程描述符知道变化,因而进程描述符也是变化的),回收--动态管理。有新的内存资源的申请,内存申请机制。
os设置n(进程数)的值,不可能无穷大因为任意时刻内存有限。os根据机器内存的不同进行不同建议。在软件设计上同样会限制进程数--系统并发度,一个常量。
若干个PCB,如何组织(数据结构--链表/索引表/线性表(简单的策略,每起一个进程则初始化一块内存,线性表相当于数组需要知道固定大小,使用和查询方便,但是‘死’--大小固定,连续存储,有时资源浪费,需求变化非常大时不足够灵活。链表离散存储,可灵活控制大小,但查询读取描述符(定位时间)花费时间较长--引人索引表。将离散的位置记录在索引表里,逻辑上连续,像中断向量表,每个中断服务的地址记录在此表。但索引表同样占用空间,算法中时间空间的矛盾但是平衡时开销比较划得来,只记录地址信息占用很少,对不同状态的进程用不同的PCB索引表),以什么方式组织数据类型)?PCB大小已知,个数上限已知,有预测地可控地管理。放在内存固定区域。
现在由于内存资源相对好些,为了管理安全,将上下文放入PCB里。
- 进程属性:PID(进程标识符,即01串);处理器状态(上下文,寄存器状态);控制信息(与调度有关,优先级、用户组、用户等等)
- 组织方式:现代os带索引表的PCB表结构。链表队列图。
- interrupt or system call -- save PCB --reload PCB-- 作为管理,切换时是无工作产出的。成本主要依赖于硬件的支持。硬件快,贵,难普遍更新换代。
- scheduling:FIFO:无优先级的方式,先进先出
- 调度类型。
-
- 从调度时间(用户多长时间才使用,长程调度一般与管理相关很少,因为功能低频率低,在早期任务时提及)和频率来分类。
- 中程调度(与os管理相关):内外存的交换(内存是处理机能访问的最大存储器),swap(不同于switch),(虚拟内存机制)。
- 微观调度(与我们关系密切,毫秒级/微秒/纳秒都可能--受制于主频,这种类型调度成本非常重要要着重考虑--关乎硬件--这种调度是关乎cpu的调度,处理器cpu选择就绪任务进入运行状态)。
- 调度模式。非抢占(占用者主动放弃资源--为什么?1时间片用完2执行完毕3等待资源,不能直接中断--管理者角度比较容易实现,不需要调度器帮忙,开销小。但是实时性差--被动)与抢占(大多os使用,急诊--优先级)。
- 进程控制。原语--一个逻辑块,对应若干语句和指令,在一个原语里不能被打断必须执行完--原语的指令一定不能很多,言简意赅,否则实时性和效率都会降低。哪些操作可以作为原语操作os需要进行衡量。典型原语操作:创建进程/撤销/阻塞/唤醒/挂起/激活--通过此进行切换--代码级。
- 创建(系统进程可以创建系统进程也可创建用户进程,创建思路不同销毁资源方式不同,相互关联时级联销毁的过程。):不是程序‘创建’进程。而是特定某进程创建进程,父子关系--不同策略--共享机制不同(全部,部分,无共享)。执行过程中根据共享机制不同,结束时制约方式不同(级联)。地址空间机制。 UNIX例子。
- 结束:取决于创建的时候做了什么。创建时申请,释放时的彻底性(以及级联释放)。
- 协作(ch7 交互机制):提高速度(一个任务可以多个进程一起做?)模块化 直接制约--直接关系,有意识地--相交进程间。无意识地制约,有中介,则在相交或无关进程中。