进程间通信
竞争条件
两个或多个进程读写某些共享数据,而最后的结果取决于进程运行的精确时序,称为竞争条件。
临界区
对共享内存进行访问的程序片段称作临界区域。 避免竞争条件解决方案的四个条件: 任何两个进程不能同时处于其临界区。 不应对CPU的速度和数量做任何假设。 临界区外运行的进程不得阻塞其他进程。 不得使进程无限期等待进入临界区。
忙等待的互斥
忙等待可能造成优先级反转
- 屏蔽中断(只能屏蔽当前CPU)
- 锁变量
- 严格轮换法 连续测试一个变量直到某个值出现为止,称为忙等待。这种方式浪费CPU时间,通常应该避免。只有在有理由认为等待时间是非常短的情形下,才使用忙等待。用于忙等待的锁,称为自旋锁。
- Peterson解法
- TSL指令(test and set lock) 硬件方案
睡眠与唤醒
进程通信原语:sleep和wakeup
信号量
三个信号量实现生产者—消费者问题 full empty mutex
互斥量
如果不需要信号量的计数能力,有时可以使用信号量的一个简化版本,称为互斥量。
- 快速用户区互斥量futex
- pthread中的互斥量
管程
管程是一个语言概念,只有少数语言实现了管程。 管程是一个过程,变量及数据结构组成的一个集合。 同一时刻只能有一个线程进入管程。 信号量操作是成对出现的,管程只需要包装一个过程。
消息传递
管程和信号量是用来解决访问公共内存的一个或多个CPU上互斥的问题。如果一个分布式系统具有多个CPU,并且每个CPU拥有自己的私有内存,他们通过一个局域网项链,那么这些原语将失效。并且这些原语没有解决机器间的信息交换方法。 上面提到的方法就是消息传递。
屏障
除非所有进程就绪准备着手下一个阶段,否则任何进程都不能进入下一个阶段,可以通过在每一个阶段的结尾安置屏障来实现这种行为。
避免锁:读-复制-更新
确保每个读操作要么读取旧的数据版本,要么读取新的数据版本,但绝对不能时新旧数据的一些奇怪组合。
调度
多个进程或线程争夺一个CPU时,选择下一个要运行的进程工作称为调度程序,改程序使用的算法称为调度算法。
调度简介
- 进程行为 几乎所有进程的(磁盘或网络)I/O请求和计算都是交替突发的。当一个进程等待外部设备完成工作而被阻塞时,才是I/O活动。 花费了绝大多数时间在计算上的是计算密集型,花费了绝大多数时间在I/O上的是I/O密集型。
- 何时调度 在创建一个新进程之后 在一个进程退出时必须做出调度决策 在一个进程阻塞在I/O和信号量上或由于其他原因阻塞时 在一个I/O中断发生时 根据如何处理时钟中断,可以把调度算法分为两类:非抢占式和抢占式
- 调度算法分类 三种环境:批处理,交互式,实时。
- 调度算法的目标 所有系统 公平-给每个进程公平的CPU份额 策略强制执行-保证规定的策略被执行 平衡-保持系统的所有部分都忙碌 批处理系统 吞吐量-每小时最大作业数 周转时间-从提交到终止间的最小时间 CPU利用率-保持CPU始终忙碌 交互式系统 响应时间-快速响应请求 均衡性-满足用户的期望 实时系统 满足截止时间-避免丢失数据 可预测性-在多媒体系统中避免品质降低
批处理系统调度
- 先来先服务
- 最短作业优先
- 最短剩余时间
交互式系统中的调度
- 轮转调度
- 优先级调度
- 多级调度
- 最短进程优先
- 保证调度
- 彩票调度
- 公平分享调度
实时系统中的调度
实时系统分为硬实时和软实时 实时系统按事件响应方式分类分为周期性和非周期性 满足一定条件的实时系统是可调度的
策略和机制
调度机制与调度策略分离,将调度算法参数化
线程调度
用户级线程:不同进程中的线程调度相互独立,内核选取进程 内核级线程:内核选取线程 用户及线程切换只需要少量的机器指令,而内核级线程需要完成的上限文切换
经典的IPC问题
哲学家就餐问题
拿起左叉,查看右叉是否可用,如果不可用等待随机时间放下左叉,重复整个过程。此方案依赖随机数,不完全可靠。 使用一个二元信号量对调用think之后的五个语句进行保护。有性能问题。 使用一个数字跟踪一个哲学家是在进餐,思考还是饥饿。以哲学家的状态判断叉子的状态。从以叉子为核心到以哲学家为核心。
读者-写者问题
读写锁,写者等待当前正在工作的读者。