1. 概述
计算机体系结构图:(CPU,memory,devices)
指令:操作码,操作数
OS作用:管理各部件;为上层的应用软件提供一个易于理解和编程的接口
历史:1950s,无操作系统,卡片;60s,单道批处理,出现了通道技术和中断技术;70s,多道批处理,任务并行执行;70s后,分时系统,多个用户连接同一台计算机;
类型:批处理;分时操作系统;实时操作系统(工业控制,军工产业);嵌入式操作系统;个人PC;分布式操作系统;
OS需要的硬件特性:
a. 受保护的指令(只有OS才有权限):IO的直接访问,内存管理状态操作的指针;特殊状态位的设置指令;停机指令;
实现方式:将CPU的状态分为管态(内核态)和目态(用户态)
程序状态字PSW:一个寄存器,存储CPU的工作状态码(管态还是目态)、条件码(指令执行后的结果特征??)、中断屏蔽码(是否屏蔽中断)
状态变化:管态->目态(直接修改PSW);目态->管态(无法修改,只能通过系统调用)
b. 系统调用:CPU执行访管指令,引起访管中断->保存上下文(PSW, PC, 及寄存器),切换到管态->中断程序执行->恢复上下文,CPU设为目态,回到中断点
c. 内存保护:进程之间互不打扰;OS不受用户程序的打扰
基址寄存器,边界寄存器;虚拟存储技术(内外存结合,硬件提供虚、实地址映射的机制)
d. 中断机制:由于某个事件的发生,改变了CPU上执行指令的顺序;该事件对应于CPU芯片内或外的硬件电路信号
中断类别:
I 同步中断(由CPU产生的中断,“异常”):错误,陷阱,终止abort,特权指令等;程序设定的异常,如程序员通过int, int3指令发出中断指令;
II 异步中断:IO中断;不可屏蔽中断(断电,硬件故障)
中断向量表0-255
e. IO 系统
f. 时钟系统:进程时间片轮转;时间信号
2. 进程管理
a. 进程:code, data, registers, heap, stack, 系统资源
stack:暂存功能,程序上下文,函数调用的局部变量和参数
内存分布状况:操作系统--代码--堆--栈--全局变量
b. 进程的特点:动态性、独立性、并发性
技术上来说:进程的创建只能通过fork进行
进程的状态:Running, blocked, ready
c. 进程实现,进程控制块PCB:
进程管理的信息:registers, pc, stack pointer, priority, process state...
内存信息:pointer to text / data / stack segment
文件管理:user id, group id, working directory ...
d. 状态队列:不同的状态用不同的队列表示,采用链表实现,链接PCB
e. 线程:实体之间可以并发执行,实体之间共享地址空间;进程=线程+资源平台;
每个线程有自己独立的:registers, pc, program status word, stack pointer, priority
进程的其他资源则被所有线程共享:包括进程管理信息、内存信息和文件信息
f. 线程和进程的比较:
进程是资源分配的单位,线程是CPU调度的单位;
进程有完整的资源平台,线程只独享必不可少的资源;
线程和进程一样,有就绪、阻塞和执行三个状态;
线程能减少并发执行的时间和空间开销;
g. 进程通信与同步:低级的通信(信号signal 信号量 semaphore),高级通信(共享内存,消息传递,管道)
并发进程之间的关系:相互独立、相互关联
进程间互斥:访问共享资源;
g1
基于关闭中断的互斥实现:一个进程进入临界区后,关闭所有中断,退出临界区时,再打开中断;原因:进程的切换是由中断进行的,关闭中断后,其他进程无法进入;
g2
基于繁忙等待的互斥实现:
1.加锁标志位:while(lock); lock = 1; ... lock = 0; 可能出现对lock的竞争
2.强制轮流发:控制进程按照轮流的方式进入临界区;
3.peterson 方法(加入了interested数组):enter_regin(pid); 临界区; leave_regine(pid)
基于繁忙等待的实现,浪费CPU资源,有可能出现死锁;
解决之道:采用阻塞sleep 和唤醒wake up机制
g3
互斥问题:两个或多个进程想进入临界区,任意时刻只允许N>=1个进程进入临界区。
信号量:semaphore 可正可负,正表示空闲资源的数量,负表示等待进入临界区的进程个数;
信号量由操作系统维护,用户只能通过初始化和两个原语(PV)访问,初始化指定一个非负整数,即空闲资源总数;
PV原语包含阻塞和唤醒机制:
P原语:申请一个空闲资源,信号量减一,成功,则退出;失败,则阻塞进程;
V原语:释放一个被占用的资源,信号量加1,发现一个被阻塞的进程唤醒;
h. 进程间同步
h1
采用两个信号量,实现缓冲区的数据存放 和数据打印 功能:
进程1: P(Buffer) ... V(Data)
进程2: P(Data) ... V(Buffer)
h2
生产者,消费者问题;贴个代码……我是得多懒~
void producer(void){ int item; while(TRUE){ item = produce_item( ); // 制造一个产品 P(BufferNum); // 是否有空闲缓冲区 P(Mutex); // 进入临界区 insert_item(item); // 产品放入缓冲区 V(Mutex); // 离开临界区 V(ProductNum); // 新增了一个产品 }}void consumer(void){ int item; while(TRUE){ P(ProductNum); // 缓冲区中有无产品 P(Mutex); // 进入临界区 item = remove_item( ) // 从缓冲区取产品 V(Mutex); // 离开临界区 V(BufferNum); // 新增一个空闲缓冲区 consume_item(item); // 使用该产品 }}
h3 哲学家就餐问题
i 进程调度
进程分类:CPU繁忙进程,IO繁忙的进程;
调度方式:不可抢占调度(每个进程运行到被阻塞);可抢占调度方式;
不同OS调度方式不同:批处理(不可抢占);交互式(可抢占);实时(可抢占,进程短)
调度算法的目标:
周转时间:平均周转时间;平均带权周转时间,权值是实际运行时间的倒数
等待时间(就绪队列中等待的时间),响应时间
吞吐量:单位时间内完成的任务量
CPU利用率
批处理的调度算法:先来先服务FCFS, 短作业优先SJF
时间片轮转算法RR:就绪队列形成一个队列,每次取一个进程执行时间片q,如果q执行完,将进程移到最后,否则,进程结束或被结束,则让出cpu,进程放入阻塞队列或退出;
特点:公平性,q的大小难以确定
优先级算法PS priority schedule:
优先级静态:高优先级会一直占用CPU
动态调整优先级:根据运行时间和等待时间调整优先级,每执行一个时间片,优先级降低;在就绪队列中等待时间越长优先级越高;
可以将优先级分成几个级别,每个级别采用时间片轮转算法;
优先级反转?
多级反馈队列 MQ:
多个就绪队列,根据进程的性质进行划分(系统进程,用户进程,批处理进程);
不同的队列优先级不同;
不同的队列采用不同的调度算法:FCFS, RR
需要面对的问题:队列的个数;每个队列的算法;升级/降级的算法;确定进程初始队列的方法;
可以采用等待时间和执行时间进行调整
其他调度算法:转自:http://www.blogjava.net/killme2008/archive/2009/06/28/284459.html
6、其他调度算法,保证调度算法保证每个进程享用的CPU时间完全一样;彩票调度算法是一种概率调度算法,通过给进程“发彩票”的多少,来赋予不同进程不同的调用时间,彩票调度算法的优点是非常灵活,如果你给短任务发更多“彩票”,那么就类似STCF调度,如果给每个进程一样多的“彩票”,那么就类似保证调度;用户公平调度算法,是按照每个用户,而不是按照每个进程来进行公平分配CPU时间,这是为了防止贪婪用户启用了过多进程导致系统效率降低甚至停顿。
7、实时系统的调度算法,实时系统需要考虑每个具体任务的响应时间必须符合要求,在截止时间前完成。(1)EDF调度算法,就是最早截止任务优先(Earliest deadline first)算法,也就是让最早截止的任务先做。当新的任务过来时,如果它的截止时间更靠前,那么就让新任务抢占正在执行的任务。EDF算法其实是贪心算法的一种体现。如果一组任务可以被调度(也就是所有任务的截止时间在理论上都可以得到满足),那么EDF可以满足。如果一批任务不能全部满足(全部在各自的截止时间前完成),那EDF满足的任务数最多,这就是它最优的体现。EDF其实就是抢占式的STCF,只不过将程序的执行时间换成了截止时间。EDF的缺点在于需要对每个任务的截止时间做计算并动态调整优先级,并且抢占任务也需要消耗系统资源。因此它的实际效果比理论效果差一点。(2)RMS调度算法,EDF是动态调度算法,而RMS(rate monotonic scheduling)算法是一种静态最优算法;该算法在进行调度前先计算出所有任务的优先级,然后按照计算出来的优先级进行调度,任务执行中间既不接收新任务,也不进行优先级调整或者CPU抢占。因此它的优点是系统消耗小,缺点就是不灵活了。对于RMS算法,关键点在于判断一个任务组是否能被调度,这里有一个定律,如果一个系统的所有任务的CPU利用率都低于ln2,那么这些任务的截止时间均可以得到满足,ln2约等于0.693147,也就是此时系统还剩下有30%的CPU时间。这个证明是Liu和Kayland在1973年给出的优先级反转:
1、什么是优先级反转?
优先级反转是指一个低优先级的任务持有一个被高优先级任务所需要的共享资源。高优先任务由于因资源缺乏而处于受阻状态,一直等到低优先级任务释放资源为止。而低优先级获得的CPU时间少,如果此时有优先级处于两者之间的任务,并且不需要那个共享资源,则该中优先级的任务反而超过这两个任务而获得CPU时间。如果高优先级等待资源时不是阻塞等待,而是忙循环,则可能永远无法获得资源,因为此时低优先级进程无法与高优先级进程争夺CPU时间,从而无法执行,进而无法释放资源,造成的后果就是高优先级任务无法获得资源而继续推进。2、解决方案:(1)设置优先级上限,给临界区一个高优先级,进入临界区的进程都将获得这个高优先级,如果其他试图进入临界区的进程的优先级都低于这个高优先级,那么优先级反转就不会发生。(2)优先级继承,当一个高优先级进程等待一个低优先级进程持有的资源时,低优先级进程将暂时获得高优先级进程的优先级别,在释放共享资源后,低优先级进程回到原来的优先级别。嵌入式系统VxWorks就是采用这种策略。 这里还有一个八卦,1997年的美国的火星探测器(使用的就是vxworks)就遇到一个优先级反转问题引起的故障。简单说下,火星探测器有一个信息总线,有一个高优先级的总线任务负责总线数据的存取,访问总线都需要通过一个互斥锁(共享资源出现了);还有一个低优先级的,运行不是很频繁的气象搜集任务,它需要对总线写数据,也就同样需要访问互斥锁;最后还有一个中优先级的通信任务,它的运行时间比较长。平常这个系统运行毫无问题,但是有一天,在气象任务获得互斥锁往总线写数据的时候,一个中断发生导致通信任务被调度就绪,通信任务抢占了低优先级的气象任务,而无巧不成书的是,此时高优先级的总线任务正在等待气象任务写完数据归还互斥锁,但是由于通信任务抢占了CPU并且运行时间比较长,导致气象任务得不到CPU时间也无法释放互斥锁,本来是高优先级的总线任务也无法执行,总线任务无法及时执行的后果被探路者认为是一个严重错误,最后就是整个系统被重启。Vxworks允许优先级继承,然而遗憾的工程师们将这个选项关闭了。(3)第三种方法就是使用中断禁止,通过禁止中断来保护临界区,采用此种策略的系统只有两种优先级:可抢占优先级和中断禁止优先级。前者为一般进程运行时的优先级,后者为运行于临界区的优先级。火星探路者正是由于在临界区中运行的气象任务被中断发生的通信任务所抢占才导致故障,如果有临界区的禁止中断保护,此一问题也不会发生。