一、并发:一个CPU交替执行多个程序
由于程序在执行涉及到磁盘的操作会特别慢,因此可以在程序执行磁盘操作的时候切换到其他程序。除了改变PC指针以外,还需要保护现场,用PCB来记录。
进程控制块(PCB):操作系统管理控制系统运行所用的集合信息
1)进程标识信息:本进程,父进程,用户
2)处理机器状态信息保存区:寄存器,栈指针
3)控制信息:调度和状态信息,进程间通信信息,存储管理信息
进程:一个具有一定独立功能的程序在数据集合上的一次动态执行过程。应该包括代码,数据,程序计数器中的值(下一条指令的地址PC),寄存器,系统资源(打开的文件等)。从内核的角度来看,进程由用户内存空间(数据和代码)和内核数据结构(维护进程状态的信息,进程号,虚拟内存表,信号)组成
进程生命周期:
三种基本状态:
1)running:正在使用CPU
2)ready:获得了除了CPU之外的所有资源
3)waiting:正在等待某一个事件或者资源
进程挂起:进程的映像在磁盘上
状态队列:操作系统为每种状态的进程维护一组队列,每个进程的PCB会加入该队列中。
线程
每个线程有自己的控制模块TCB,独立的寄存器、堆栈,共享数据、文件。
**用户级线程:**使用线程函数库来完成,用户可以指定线程的调度。
两个线程切换的时候,如果使用一个栈的话会导致错误,因此需要使用两个栈。首先需要切换栈,用TCB记录栈的指针。
内核级线程:
(有时间看哈工大视频再补充)
创建进程:
fork()函数:把进程当前的状态复制一遍,父进程可以wait()等待,直到子线程exit()或者和子线程并发执行
能够返回两次,父进程中返回子进程的PID,子进程返回0,出现错误返回负数(errno=EAGAIN,表示进程数达到了系统规定上限,errno=ENOMEM表示内存不足)
首先分配新的虚拟内存,建立段表页表,和父进程共享物理内存,添加子进程PCB到系统进程链表当中。如果有一个进程要对物理内存进行修改,才会重新分配一个物理内存,将东西复制过去。
加载进程:
**exec()函数:**根据路径名来找到可执行文件,并代替.text,.data,.bss以及堆栈里面的内容。除了进程号其他的都被替代,并且运行。执行一次没有返回。
等待、终止进程:
exit():进程调用exit(),会返回一个值,释放内存等资源,但是PCB还存在。检查父进程是否活着,活着的话会保留这个值,进入僵尸状态(exit()和wait()之间),直到父进程回收;否则的话init进程会成这个进程的父进程,会进行回收。只能由父进程终止子进程,
**wait():**父进程需要等待子进程结束,调用wati()将子线程的PCB回收。
二、进程调度:
需要进行调度的情况:
1)running切换到waiting
2)running切换到ready
3)running切换到exit
4)waiting切换到ready
只能在(1)(3)进行调度为非抢占调度,(2)(4)为非抢占
抢占调度当一个进程使用CPU,只能等该进程结束或者切换到waiting,才能调度
FCFS:就绪队列中,先执行先入队的。不可抢占
短任务优先(SJF):每次给执行长度最短的进程分配CPU,因为无法确切地知道进程的长度,因此使用第n次的猜测值和第n次的实际值做加权平均的方法来预测n+1的执行长度。假设一个进程A正在执行,如果一个执行时间更短的进程B加入到ready序列中,抢占式分配策略会先执行B,把余下的A加入ready中;非抢占式会让A先执行完。实际上是优先级调度的特例。系统会根据进程的内存要求、打开文件数、平均IO执行时间作为一个进程的优先级。这样的话可能会造成低优先级的进程的饥饿。因此通过老化来解决,随着在ready队列中的等待时间的增加,优先级提高。
轮转算法(RR)(抢占式): 给每个进程加一个时间片,执行时间不得大于该时间片。执行一个进程会有一个定时器,当一个进程执行时间小于一个时间片,会自动释放内存,否则会切换上下文,将该进程加入到ready队列的尾部。由于每次都需要切换上下文,因此时间片的大小应该大于上下文切换的时间,时间片过大就退化成了FCFS。(时间片大于80%的指令)
多级队列调度:ready队列被划分成独立的队列,不同队列之间有优先级,每个队列都有自己的调度策略。高优先级的进程会抢占低优先级的进程,这样也会造成优先级低的进程饥饿。
因此出现了多级反馈队列调度**,允许进程在不同的队列之间进行移动。优先级越高的队列分配的时间片越少,如果一个进程的执行时间长于一个时间片,则会降级。最后形成CPU密集型进程优先级低,IO密集型进程优先级高