操作系统 2. 进程与线程 2021-04-06 浏览量 826 暂无评论 #### 操作系统之进程与线程 - [x] L8 CPU管理的直观想法 2021-03-19 管理CPU IO指令执行特别慢,比计算语句为10^6:1,如果计算指令与IO指令顺序执行,CPU利用率特别低,要提高CPU的利用率,多道程序交替执行 ![](http://10.255.249.210/Jineng/picture-bed/uploads/3087a1f70e68d4cb659436fbe5567c13/20210319213958.png) 并发:多道程序放在内存中,CPU交替执行,切过去,切回来(改PC,即IP) 怎么实现这种交替执行呢? - 记录返回地址和继续执行需要的数据 进程:进行中的程序 - [x] L9 多进程图像(Multiple Processes) 2021-03-20 用户创建多个进程,操作系统使用PCB(Process Control Block)记录这些进程,按合理的次序推进 多进程图像从启动开始到关机结束 main中的fork()创建了第一个进程,init执行了shell(Windows桌面) `if(!fork) {init();}` shell再启动其他进程 ```cpp int main(int argc, char* argv[]) { while(1) { scanf("%s", cmd); if(!fork()) {exec(cmd);} wait(); } } ``` 多进程的组织:PCB+状态+队列 交替:队列操作(设计到怎么取下一个进程)+调度+切换 ```cpp // 要使用汇编来精细控制 switch_to(pCur,pNew) { pCur.ax = CPU.ax; pCur.bx = CPU.bx; ... pCur.cs = CPU.cs; pCur.retpc = CPU.pc; CPU.ax = pNew.ax; CPU.bx = pNew.bx; ... CPU.cs = pNew.cs; CPU.retpc = pNew.pc; } ``` 如何解决多进程间的相互影响?多进程的地址空间分离(内存管理,映射表) 如何解决多进程间的相互合作?进程同步(锁!切换条件,检查锁,上锁,开锁) `fork()`:在现有进程中创建子进程,子进程是父进程的副本,它将获得父进程数据空间、堆栈等资源的**副本**,后面需要使用时,再分离修改。 - [x] L10 用户级线程(User Threads)yield 2021-03-20 进程 = 资源 + 指令执行序列 如果能将资源和指令执行分开,切换指令而资源不变,岂不美哉?==>线程(映射表不变而PC指针变) 线程和进程肯定都有自己适用的地方 线程: 概念:多个执行序列 + 一个地址空间 适用场景:多个线程配合完成一个任务,不需要地址隔离 实现:`pthread_create`创建,`yield`切换 存在的问题:如果两个线程共用一个栈,那么切换会出问题,线程内部函数切换和线程间切换就乱套了 解决:当然是隔离栈啦 ```cpp // 寄存器esp指向当前栈的指针 void Yield() { TCB2.esp = esp; esp = TCB1.esp; jmp xxx; // 这句话应该去掉,不然后面的}无法执行,少弹(ret)了一次栈 } // 创建TCB,并和栈关联 void ThreadCreate(A) { TCB *tcb = malloc(); *stack = malloc(); *stack = A; tcb.esp = stack; } ``` 缺点:如果一个线程进入内核后发生阻塞(如访问网卡IO,访问硬件需要通过内核),那么内核将会切换到其他进程,看不到这个线程后的其他线程,但是核心级线程是在内核中,并发性更好 - [x] L11 核心级线程(Kernel Threads)schedule 内核级线程才能真正发挥多核CPU的功能,因为用户级线程无法对硬件进行分配 多进程也不能,因为多核CPU的Cache和MMU是共享的 从用户级到内核级:两个栈到两套栈(每个都有用户栈和内核栈),内核级线程比用户级多了一步内核栈切换 那么内核栈在哪呢?中断进入(INT)内核时自动启用内核栈(硬件实现),IRET退出 - [x] L12 核心级线程实现实例 2021-03-22 没有实际写代码,对汇编和C要求很高 - [x] L13 操作系统的那棵树 2021-03-23 梳理怎样从简单的顺序执行到用户态多进程再到内核态多进程 - [x] L14 CPU调度策略 根据任务需求综合考虑:响应时间,周转时间,系统内耗(切换次数) 前台任务、后台任务;IO约束型、CPU约束型 常见的调度算法: 1. First Come, First Served (FCFS) ![](http://10.255.249.210/Jineng/picture-bed/uploads/6e338298c1a3294bc9f32fefcb431efd/20210323204444.png) 2. 短作业优先(SJF)那怎么知道谁长谁短呢? 周转时间最短(后台任务),但是响应时间得不到保证 3. 轮转(RR)按时间片轮转调度 响应时间可以得到保证(前台任务),通过时间片大小控制,但是要控制进程数N 4. 优先级调度 前台任务优先级大于后台任务,但只用优先级调度会造成后台任务饥饿 如果后台任务优先级动态升高,前台的响应时间又得不到保证 如果前后台都是用时间片,那后台任务的SJF又得不到体现 - [x] L15 一个实际的schedule函数 2021-03-23 ```cpp void Schedule(void) { while(1) { c = -1; next = 0; i = NR_TASKS; p = &task[NR_TASKS]; // 这句话没明白;明白了(数组的末尾存放PCB) while(--i) // 下面的p没变吧;PPT中的程序少了 { if(!*--p) continue; // counter既有优先级的作用,又有时间片的作用 if((*p)->state==TASK_RUNNING&&(*p)->counter>c) c = (*p)->counter, next = i; // 找到就绪态counter最大的进程 } if(c) break; for(p=&LAST_TASK;p>&FIRST_TASK;--p) { if(*p) // 保证进入IO的进程再出来后优先级变大 (*p)->counter = ((*p)->counter>>1) + (*p)->priority; } } switch_to(next); } // counter时间片的作用 void do_timer(...) { if (--(current->counter)>0) return; current->counter = 0; // 到点就执行 schedule(); } ``` - [x] L16 进程同步与信号量 2021-03-24 场景:进程合作,多进程共同完成一个任务 只发信号不能处理多对多(多个生产者消费者)的问题,需要使用信号量 生产进程,消耗进程 - [ ] L17 对信号量的临界区保护 2021-03-25 问题: 不同进程共同修改(调度)信号量时可能会出错,导致信号量的含义不对。 ![](http://10.255.249.210/Jineng/picture-bed/uploads/38aed98be13ce55482e8b0e6c4a6f9d2/20210325214033.png) 解决方案: 上锁保护,修改信号量的代码放在临界区(一次只允许一个进程进入的该进程的那段代码) 临界区代码的保护原则: 1. 互斥进入; 2. 有空让进; 3. 有限等待 第一种:对称法容易造成卡死,非对称=轮转+标记(Peterson算法) 两个进程:Peterson算法 多进程:面包店算法(复杂) 第二种:硬件阻止另一个进程进入临界区,也就是阻止调度=>关中断(cli,sti),但是多核时不好使,只能控制一个CPU 第三种:硬件原子指令 ![](http://10.255.249.210/Jineng/picture-bed/uploads/5ba64d828ac06743d3a169f7a206a894/20210325222747.png) - [x] L18 信号量的代码实现 2021-03-26 很隐蔽的队列:编译的时候,tmp放在当前进程的内核栈中,那么task_struct就能找到tmp,tmp又指向前一个task_struct ![](http://10.255.249.210/Jineng/picture-bed/uploads/2e65a2cafb0a6c339dc399f3ef0b5143/20210326205704.png) - [x] L19 死锁处理 2021-03-26 多进程环路等待 成因(比如信号量临界区的上锁和解锁间加入了别的信号量): 1. 互斥使用; 2. 不可抢占; 3. 请求和保持; 4. 循环等待。 解决方案: 1. 死锁预防(资源浪费); 2. 死锁避免,判断系统中的所有进程是否存在一个可完成的执行序列,即安全状态(银行家算法,时间复杂度高),如果可能产生死锁,则拒绝此次资源申请; 3. 死锁检测+恢复,不每次申请的时候都执行银行家算法,转而定时检测或者发现资源利用率低的时候检测(但发现问题时想回滚挺麻烦); 4. 死锁忽略(因为最简单,而且出现死锁的概率小,并且重启可以解决,都采用这个方法我笑了) 赞赏 微信支付 支付宝支付