1、进程:操作系统最核心的概念是进程。
进程是操作系统提过的最古老也是最重要的抽象概念之一。
一个进程是一个正在执行程序的实例,包括程序计数器、寄存器和变量的当前值。
2、伪并行:任何多道程序设计系统中,CPU由一个进程快速切换到另一个进程,每个进程各运行及时或者几百毫秒。实际上每一瞬间CPU只运行一个进程,但是1秒内可以运行多个进程。
硬件并行:多处理器系统中有着两个或者多个CPU共享同一物理内存,可以同时运行多个进程。
3、进程的创建:4个主要事件会导致进程的创建
1)系统初始化
2)正在运动的程序执行了创建进程的系统调用
3)用户请求创建一个新进程
4)一个批处理作业的初始化
UNIX中,fork创建进程时,系统调用创建一个与调用进程相同的副本,后续子进程执行execve(或类似的系统调用)改变其内存映像并运行新程序
windows中,Win32程序调用CreateProcess处理进程的常见及新程序的装载。
进程创建之后,UNIX和windows的父进程和子进程的地址空间不同,刚创建时,UNIX的父进程和子进程的地址空间相同。
4、进程的终结
1)正常退出(自愿)
2)出错退出(自愿)
3)严重错误(非自愿)
4)被其他进程杀死(非自愿)
5、进程的状态
1)运行态
2)就绪态
3)阻塞态
6、进程的层次
UNIX中,进程和它的所有子进程和后裔共同组成一个进程组。 整个系统中所有的进程都属于init为根的一棵树。
windows中没有进程层次,所有的进程地位相同。 创建进程的时候父进程从子进程处获得一个句柄,可以用句柄来控制子进程,同时句柄可以传送给其他进程。
7、调度算法:决定 运行哪一个程序、何时运行、运行多长时间。
8、进程的实现:操作系统维护一张进程表,每个进程占用一个进程表项,包含了进程状态的重要信息(程序计数器、堆栈指针、内存分配状况、所打开文件的状态、账号和调度信息,以及进程状态切换中必须保存的信息。)
9、进程中断发生后操作系统最底层的工作步骤
一、硬件
①、硬件将进程的程序计数器、程序状态字、寄存器等压入堆栈;
②、跳转到中断向量指示的地址,装入新的程序计数器;
二、软件
③、汇编语言过程保存寄存器值;
④、汇编语言过程设置新的堆栈;
⑤、C中断服务例程运行;
⑥、调度程序决定下一个将运行的进程;
⑦、C过程返回至汇编代码;
⑧、汇编语言开始运行新的当前进程。
一个进程执行过程中可能发生数千次中断,每次中断后进程都可以返回到中断发生之前的状态。
10、多道程序设计模型:从概率的角度查看CPU的利用率
11、线程:
并行实体拥有共享同一地址空间和所以可用数据的能力;
线程类似于轻量级的进程,创建、撤销的性能更好(快速);
针对存在大量计算和I/O处理的程序,多线程允许彼此的活动重叠进行,加快程序的执行速度。
多CPU系统中的多线程,让真正的并行有了实现的可能性。
进程拥有线程,用于把资源集中到一起;线程中包括程序计数器、寄存器,是再CPU上被调度执行的主体。
每个进程中的内容(线程共享) | 每个线程中的内容(线程独有) |
地址空间、全局变量、 打开文件、子进程、 即将发生的定时器、 信号与信号处理程序、 账户信息 | 程序计数器、 寄存器、 堆栈、 状态 |
线程的状态:运行、阻塞、就绪、禁止
每个线程有自己的堆栈:各线程会调用不同的过程,产生不同的执行历史。
线程引入的复杂性:不同的线程处理同一个文件时,一个线程关闭的文件,另一个线程再次写入信息会出错;
父进程和子进程的线程一样时,父进程进行read系统调用(键盘)时被阻塞,子进程什么状态?键盘输入信息后,两个进程分别得到什么信息,还是某一个得到?
网络传输时会有同上的问题。
12、服务器构建模型
模型 | 特性 |
多进程 | 并行性、阻塞系统调用 |
单线程进程 | 无并行性、阻塞系统调用 |
有效状态机 | 并行性、非阻塞系统调用、中断 |
13、用户空间中实现线程:采用线程包创建、撤销线程
用户空间中的线程在一个运行时系统上运行,每个运行时系统对于一个线程,包含了专用的线程表,用于记录线程的属性。
优点
线程切换的速度快:至少比陷入内核快一个数量级;
允许每个进程定制自己的调度算法;
缺点
当前线程阻塞系统调用(缺页中断问题)可能会影响其它线程;
线程无法采用轮转调度的方式调度线程。(单独的进程内部没有时钟中断)
14、内核中实现线程:采用系统调用创建、撤销线程
线程的回收方式:选择将线程标记为不可运行状态而不是不销毁线程,需要创建线程时重新启用不可运行状态的线程。
问题:多线程进程创建新进程:根据使用目的决定继承一个线程(调用exec启动新程序)还是相同数量线程(程序继续运行)。
15、内核、用户空间混合实现
使用内核级线程、将用户级线程与内核线程多路复用。
内核识别内核线程并进行调度,内核线程会被多个用户级线程多路复用:创建、撤销、调度。
16、调度程序激活机制(模拟内核线程)
上行调用:内核已知线程的阻塞或者就绪“状态”,并依此翻出相应的“信号”对线程实现调度。
17、弹出式线程:一个消息到达导致创建一个线程来处理该消息。内核中的弹出式线程比用户空间中的容易、快捷
18、单线程代码多线程化的困难:
全局变量问题(重复修改)--- 线程私有的全局变量
库过程不可重复调用问题;信号处理问题;堆栈管理问题(各线程各自的堆栈导致内核无法确定是否自动增大堆栈) ---- 可能需要重定义系统调用、以及重写库
19、进程间通信
进程间通信的问题:①、一个进程如何把信息传递给另一个进程;②、确保多个进程在关键活动中不会出现交叉;③、确保进程运行的顺序正确。
线程同理,但是由于线程之间共享资源,不需要考虑信息传递的问题(①)。
20、竞争条件:多个进程读写数据时,最后的结果取决于进程运行的精确时序。
21、临界区:对共享内存进行访问的程序片段。
用于避免多个进程同时读写共享的数据。
22、并发进程使用共享数据的正确、高效条件:
①任何两个进程不能同时处于临界区;
②不应对CPU的速度和数据做任何假设;
③临界区外运行的进程不得阻塞其他进程;
④不得使进程无限期等待临界区。
22、忙等待的互斥
1)、屏蔽中断:进程进入临界区后立即屏蔽所有中断,CPU不会切换其它进程。 - 多处理器系统不可取
2)、锁变量:一个共享(锁)变量用于标记是否可以运行进程。 - 两个进程调度过程中会因锁变量信息产生预期之外的问题。
3)、严格轮换法:通过各自的锁变量轮流进入临界区。 - 进程速度差距较大时,轮流进入临界区的阻塞期过长。
4)、Peterson解法:锁变量和警告变量结合。 - 两个进程同时锁进程是,会产生预期之外的问题。
5)、TSL(测试比加锁)指令(XCHG指令):锁住存储总线,禁止写入。 - 单根系统总系可以确保这种方式的有效性。
23、睡眠与唤醒
Peterson解法和TSL(XCHG)解法都是正确的,都有忙等待的缺点,可能会导致优先级反转的现象。
无法进入临界区中采用阻塞的方式而不是忙等待,sleep&wakeup 指令。
未睡眠时收到唤醒指令,唤醒信号丢失。 解决方法:增加唤醒等待位用于记录历史,根据唤醒等待位和睡眠信号决定是否睡眠。
24、信号量:也可用于实现进程的同步
多个进程同时唤醒一个进程,唤醒等待位不足。 解决方法:唤醒等待位更新为整形变量,用于累计历史唤醒次数。
down & up:检查数值、修改变量以及可能的随眠操作均作为单一、不可分割的原子操作。 原子操作-要么不间断执行,要么都不执行。
27、互斥量:没有计数能力的信号量
状态:解锁、加锁
数据共享方式:①、共享数据放置在内核中;②、进程间贡献部分地址空间(与线程间的区分度减弱但是存在)。
条件变量:允许线程由于一些未达到的条件而阻塞。 经常与互斥量一起使用。 条件变量不会存在内存中,因此需要考虑信号丢失的问题。
28、管程:是语言概念,C语言中不支持
一个管程是由过程、变量及数据结构等组成的一个集合。 任何时刻管程中只能有一个活动的进程,进入管程的互斥由编译器负责。
29、消息传递:使用 send和receive 实现进程间通信
send:消息传递给指定目标; receive:从指定目标接受信息,接受的信息后返回会确认信息。
方式一:确认进程的唯一地址,依此作为信息传递的依据;
方式二:创建新的数据结构-信箱,用于存储接收到的信息。
30、屏障:用于确保一组进程的同步。
31、避免锁:读-复制-更新
确保读取的数据同步保持在更新前或者更新后(原有数据保持一定的时间 -- 一个数据结构引用的最大时间)的状态。
32、调度:只有一个CPU可用是必须选择下一个要运行的进程。(进程调度的处理方法同样适用于线程调度)
好的调度程序可以提高性能和用户的满意度。
一些调度程序需要考虑电量损耗(资源不充足的情况);
调度程序还需要考虑CPU的利用率(进程切换的代价比较大):①用户态需要切换到内核态;②保存当前进程的状态(进程表中存储寄存器);③调度算法选定一个进程;④新进程的内存映像重新状态MMU;⑤新进程运行。
1)进程行为:计算密集型 和 I/O密集型
2)何时调度:①创建新进程时,运行父进程还是子进程;②一个进程退出时做出调度决策决定下一个运行进程;③进程阻塞时需要进行调度决策决定运行的进程;④发生I/O中断时做出相应的调度决策。
非抢占式调度:让一个进程运行直至被阻塞。
抢占式调度:一个进程运行某个固定时段的最大值后仍运行,挂起该进程并调度决策挑选其它进程。
3)调度算法分类:①批处理:-减少进程的切换而改善性能
②交互式:-避免一个进程霸占CPU而拒绝运行其它进程
③实时:-抢占有时不是必须的,只运行用来推进现有应用的程序。
33、调度算法的目标
1)所有系统① 公平 -给每个进程公平的CPU份额
② 平衡 -保持系统所有部分都忙碌
2)批处理系统① 吞吐量 -每小时最大作业量
② 周转时间 -从提交到终止间的最小时间
③ CPU利用率 -保持CPU始终忙碌
3)交互式系统① 响应时间 -快速响应请求
② 均衡性 -满足用户期望
4)实时系统① 满足截止时间 -避免丢失数据
② 可预测性 -在多媒体系统中避免品质降低
34、调度方式
1)批处理系统中的调度① 先来先服务 -按进程请求CPU的顺序使用CPU
② 最短作业优先 -最短作业优先,以降低平均等待时间
③ 最短剩余时间优先 -抢占式版本的最短作业优先,需要提前掌握运行时间。
2)交互式系统中的调度① 轮转调度 -每个进程分配一个时间片,允许在该时间段内运行。 较长-服务变差(对于短的交互请求);较短-降低CPU效率(进程切换较为浪费时间)
② 优先级调度 -分配进程优先级的轮转调度。 调度优先级来时间进程调度(静态赋予,动态赋予)
③ 多级队列 -进程的优先级在该进程运行一次后降低一,同时进程可运行的时间片随着优先级的降低而翻倍。
④ 最短进程优先 -为了实现最短响应时间。 根据进程过去的行为估计运行时间。
⑤ 保证调度 -计算每个进程真正使用CPU时间和应当获得CPU时间的比值(1/n),依此调度进程。
⑥ 彩票调度 -每份彩票相当于CPU运行的一个基本份额,根据进程获取彩票的数量决定运行时间。
⑦ 公平分享调度 -每个用户获取相同的CPU份额,再分配每个用户中各进程的CPU份额。
3)实时系统中的调度 硬实时:必须满足绝对的截止时间;软实时:可以容忍偶尔错失截止时间的问题。
系统可调度:各事件的CPU需求时间与对应事件的比值之和 小于 1。 假设:上下文切换(进程调度)的开销很小。
35、策略和机制 :调度机制和调度策略分离的原则。调度机制位于内核,调度策略由用户进程决定。
36、线程调度① 用户级线程 -内核不知道线程的存在,内核分配进程的时间片,进程中的线程调度决定运行的线程;
② 内核级线程 -内核选定运行的线程并赋予线程相应的运行时间片。
一般而言,用户级线程相比内核级线程可以更好的满足应用的需求。
进程间线程切换开销大于进程内的线程切换开销。