目标
作用
人工操作系统
通过纸袋输入机读取纸袋上的程序,计算完毕后将结果写入纸带,等待取走,装入纸带需要程序员操作。
脱机输入输出方式(Off-Line I/O)
将纸袋上的程序通过外围机输入到磁带上,再从磁带上调入到内穿,一定程度上解决了CPU 与 I/O 设备速度不匹配的问题。
单道批处理系统 (Simple processing system)
把一批作业以脱机的方式输入到磁带上,在监督程序的控制下,一批作业能连续的处理,内存中始终只保持只有一道作业。
多道批处理系统
作业在内存中排成一个后备队列,又作业调度程序按照某种算法去除若干个作业调入内存,使这些作业共享CPU和系统中的各种资源。
分时系统 (Time Sharing System)
利用多道程序与多任务处理使多个用户可以同时使用一台计算机。
即计算机把任务的运行时间分为多个时间段,并且将这些时间段平均分配给用户们指定的任务。轮流地为每一个任务运行一定的时间,如此循环,直至完成所有任务。
分时系统的特征:多路性,独立性,及时性,交互性。
实时系统 ( Real Time System)
实时系统是指能及时响应外部事件的请求,在规定的时间内完成对该时间的处理,并控制所有实时任务协调一致地运行。
设计实时操作系统的首要目标不是高的吞吐量,而是保证任务在特定时间内完成
系统从接收一个任务,到完成该任务所需的时间,其时间的变化称为抖动。可以依抖动将实时操作系统分为两种:硬实时操作系统及软实时操作系统
硬实时操作系统必须使任务在确定的时间内完成。软实时操作系统能让绝大多数任务在确定时间内完成。linux unix 是分时操作系统,因为可以登录多个账号,而且它是多任务执行的
并发 (Concurrence)
共享(Sharing)
又称为资源复用,是指系统中的资源可供内存中多个并发执行的进程共同使用。
资源共享方式:互斥共享,同时访问
虚拟 (Virtual)
通过“空分复用”或“时分复用”将一条物理信道编程若干条逻辑信道,使得原来只能供一对用户通话的物理信道编程能供多个用户同时通话的逻辑信息道。
时分复用技术:使用这种技术,两个以上的信号或数据流可以同时在一条通信线路上传输,其表现为同一通信信道的子信道。
空分复用技术:将一个频率范围比较宽的信道划分成为多个频率范围比较窄的信道(频带),其中每一个频带仅供一对用户使用。
异步 (Asynchronous)
进程是以人们不可预知的速度向前推进的,此即进程的异步性。
处理机管理
进程控制:为作业创建进程,终止已经结束的进程,转换正在运行的进程的状态。
进程同步:对多个进程进行协调,协调方式包括同步和互斥。对访问临界资源时采用互斥方式,相互合作时采用同步方式。
进程通信:实现相互合作的进程之间交换信息。
调度:作业调度、进程调度。
存储器管理功能
内存分配:包括静态和动态的方式。
内存保护:保证各个程序彼此不干扰,不让用户访问系统的程序和数据等。
地址映射:将地址空间中的逻辑地址转换成内存空间的物理地址。
内存扩充:借助虚拟存储技术。
设备管理功能
缓冲管理:使用缓冲技术解决设备间速度不匹配的问题。
设备分配:为程序分配需要的设备。
设备处理:又称为设备驱动,实现CPU与设备控制器之间的通信。
文件管理
文件存储空间管理、目录管理、文件的读写管理和保护
操作系统与用户之间的接口
用户接口、程序接口
现代操作系统的新功能
系统安全、网络功能和服务、支持多媒体
前趋图 (Precedence Graph):是一个有向无循环图,可以标记为DAG,用于描述进程之间的先后执行顺序,通过判断前驱图是否出现环可以判断进程是否能实现。
概念:偏序关系,前趋关系(Precedence Relation),初始节点(Initial Node),终止节点(Final Node)。
程序顺序执行的特征:顺序性,封闭性,可再现性。
程序并发执行
注意只有不存在前趋关系的程序之间才有可能并发执行。
并发执行的特征:间断性,失去封闭性,失去再现性。
进程概念的引入是为了能够对并发执行的程序加以描述和控制。
进程的定义
为了让每个并发执行的程序都能够独立地运行,在操作系统中必须为之配置一个专门的数据结构,称之为进程控制块,PCB。系统创建进程实质上就是创建PCB。系统利用PCB来描述进程的基本情况和活动过程,进而控制和管理进程。这样,又程序段,相关数据段,和PCB三部分构成了程序实体(进程映像),一般情况下我们称进程实体为进程。其他典型定义:进程是程序的一次执行;进程是一个程序及其数据在处理机上顺序执行发生的活动;
进程控制块 (ProcessControl Bolck
)
PCB一般包括:
1.程序ID(PID、进程句柄):它是唯一的,一个进程都必须对应一个PID。PID一般是整形数字
2.特征信息:一般分系统进程、用户进程、或者内核进程等
3.进程状态:运行、就绪、阻塞,表示进程现的运行情况
4.优先级:表示获得CPU控制权的优先级大小
5.通信信息:进程之间的通信关系的反映,由于操作系统会提供通信信道
6.现场保护区:保护阻塞的进程用
7.资源需求、分配控制信息
8.进程实体信息,指明程序路径和名称,进程数据在物理内存还是在交换分区(分页)中
9.其他信息:工作单位,工作区,文件信息等
进程特征
进程的基本状态
挂起操作和状态转换
挂起:挂起对应着激活,当该操作作用于某个进程时,该进程将会被挂起,进入到禁止状态。进程正在执行,它将会被暂停指定,若原本是就绪状态,则暂时不受调度。
进程管理中的数据结构
操作系统将各类资源抽象成为各种数据结构,以及提供对一组资源进行操作的命令。在计算机系统中,每个资源和每个进程都设置了一个数据结构,用于表征实体,称之为资源信息表或进程信息表,其中包含了资源或进程的表示,描述状态等信息以及一批指针。
PCB的作用
记录了操作系统中需要的,用于描述进程的当前情况以及管理进程运行的全部信息,是操作系统中最重要的记录型数据结构。
1.作为独立的运行基本单位的标志。
2.能够实现间断性运行方式。
3.提供进程管理所需要的信息。
4.提供进程调度所需要的信息。
5.实现去其他进程的同步与通讯。
PCB中的信息
进程标识符
:用于唯一地表示进程,常包括外部标识符和内部表示符。
处理机状态
:也称为处理机的上下文,主要又处理机的各种寄存器中的内容组成,包括通用寄存器,指令计数器,程序状态字
,用户栈指针。
进程调度信息
:说明进程状态和有关进程调度的信息。如:状态,优先级,事件。
进程控制信息:如进程状态,进程优先级。
PCB的组织方式
使用适当的组织方式是为了更加有效地管理PCB
线性方式:将所有PCB组织在一个线性表中,开销小,简单但是每次查找都要扫描一次,适合进程不多的系统。
连接方式:将状态相同的进程PCB分别通过PCB中的链接字组词一个队列,形成就绪队列,堵塞队列,空白队列等。
索引方式:根据进程状态建立几个索引表,在索引表目录中记录相同状态的进程地址列表。
进程控制是进程管理中最基本的功能,主要包括创建进程,终止进程,切换进程的状态等。这些控制一般有OS的内核中的原语实现。
OS内核:通常将一些与硬件紧密相关、驱动程序、运行频率高的模块安装在紧靠硬件的软件层次中,它们常驻内存,常被称为OS内核。
OS内核包好支撑和资源管理两大功能。
支撑功能:中断处理,时钟管理,原语操作。
资源管理功能:进程控制,存储器管理,设备管理。
进程的创建
在OS中,运行一个进程创建另外一个进程,因此有父进程,子进程的说法。子进程还可以继续创建更多的孙进程,因此形成了一个进程的层次结构。子进程可以继承父进程所拥有的所有资源,例如打开的文件,缓冲区等。windows中不存在进程层次结构的概念,所有的进程都拥有相同的地位。引起创建进程的事件常包括:用户登录,提供服务,应用请求,作业调度。创建步骤:申请空白PCB -> 为新进程分配所需的资源 -> 初始化PCB -> 插入就绪队列。
进程的终止
引发终止的事件:正常结束, 异常结束, 外界干预。
终止过程:读取PCB中的状态 -> 若进程处于执行状态,则立即终止,并设调度标志为真 -> 若有子孙进程,将其他子孙进程也终止 -> 将资源交换给父进程或系统 -> 将PCB从队列中移出。
进程的堵塞和唤醒
导致堵塞和唤醒的事件:请求资源失败,等待某种操作,新数据未到达,等待新任务到达。
堵塞过程:堵塞是主动行为(通过调用阻塞原语 block),首先停止执行,然后将PCB中的现行状态改成阻塞,将PCB加入到阻塞队列。最后调度程序进行重新调度,将CPU分配给其他进程。
唤醒(wakeup)的过程:将进程从阻塞队列中移出,将PCB中的现行状态改成就绪,然后加入到就绪队列中。
注意阻塞和唤醒时在不同进程中使用的,否则将会永久阻塞。
进程的挂起与激活
OS利用挂起原语(suspend)将指定进程或处于堵塞状态的进程挂起。调用激活原语(active),将指定进程激活。挂起过程:首先检查进程状态,活动就绪改成静止就绪,活动阻塞改成静止阻塞,把PCB复制到某指定的内存区域。激活过程:先将进程从外存调入内存,检查该进程的现行状态,若是静止就绪则改成活动就绪,若是静止堵塞,则改为活动堵塞。
进程同步的主要任务是对多个相关进程在执行次序上进行协调,使这些并发执行的进程之间能够按照一定的规则共享系统资源,并且很好地相互合作,从而使程序的执行具有可再现性。
基本概念
硬件同步机制
软件方法解决进程互斥进入临界区的问题有难度和很大的局限性,很少使用,计算机大多提供特殊的硬件指令来解决临界区问题。在管理临界区时,可以将标志进程看成一个锁。测试和关锁的操作是连续的。注意利用硬件指令虽然简单有效,但是必须不断地进行测试,处于一种“忙等”的状态,不符合“让权等待”的原则,浪费处理机的同时难以解决复杂的同步问题。
关中断:实现互斥的最简单方法之一。进入测试锁前关闭中断,直到完成锁测试并上锁后才能打开在端。关中断不适用于多cpu
系统。
Test-and-set指令实现互斥。
借助一条硬件指令实现互斥。
//一般性描述
bool TS(bool *lock){
bool old = *lock;
*lock = true;
return old;
}
//使用:
while(TS(&lock))...;
利用Swap指令实现进程互斥。
Swap指令又称为对换指令,用于交换两个字的内容。可以简单有效地实现互斥。
//过程描述
void swap(bool *a, bool *b){
bool tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
//使用
do{
key = true;
do {
swap(&lock, &key);
}while(key!=false);
//临界区操作
lock=false
}while(true);
信号量机制
Dijkstra
提出信号量(semaphores
)机制,是一种进程同步工具。现在广泛用于单片机处理和多处理机系统和计算机网络中。
信号量:信号量(semaphore
)的数据结构为一个值和一个指针,指针指向等待该信号量的下一个进程。信号量的值与相应资源的使用情况有关。当它的值大于0时,表示当前可用资源的数量;当它的值小于0时,其绝对值表示等待使用该资源的进程个数。
Dijkstra
将整型信号量用于表示一个资源数目的整型量S,仅能通过两个标准的原子操作wait(S) 和signal(S)来访问。这两个操作被称为P,V锁。也可以记为“P操作”和“V操作”。 wait(S){ //p操作
while (S<=0);
S=S-1;
}
signal(S){ //v操作
S=S+1;
}
typedef struct{ //记录型信号量可描述为
int value;
struct process *L;
} semaphore;
void wait (semaphore S) { //相当于申请资源
S.value--;
if(S.value<0) {
add this process to S.L;
block(S.L);
}
}
void signal (semaphore S) { //相当于释放资源
S.value++;
if(S.value<=0){
remove a process P from S.L;
wakeup(P);
}
}
上述进程互斥问题都是针对一个临界资源而言的,在有些应用场合,一个进程需要同时获得两个或者更多的资源。AND信号量可以解决多临界资源申请问题。其基本思想是将程序运行需要的所有资源一次性分配给进程,等进程使用完毕后在一起收回。假设有S1,…Sn,N个资源,进程必须申请到所有资源后才可执行,则其wait 和signal描述为:
void wait(S1, S2, ... , Sn){
if (S1>=1 && S2>=1 && ... && Sn>=1 )
for (int i=1; i<n; i++)
Si = Si - 1;
else
place this process//将当前进程放置在第一个不满足Si>=1的阻塞队列中
}
void signal(S1, S2, ... , Sn){
for (int i=1; i<n; i++)
Si = Si + 1;
romove all the process //将si中的放到就绪队列
}
在记录型信号量机制中,wait和signal操作只能进行加一减一的操作。当需要一次性需要申请N个同类资源时,需要进行N次操作,这显然是低效的。为方便对资源的控制,每种资源在分配前需要检查其数量是否在其极限值之上。信号量集是对AND信号量进行扩充,申请和释放操作的测试值可以大于1,并且可以在一次操作中测试所有资源。
//S为信号量,d为需求量,t为下限值
void swait(S1, d1, t1, S2, d2, t2, ... , Sn, dn, tn){
if (S1>=t1 && S2>=t2 && ... && Sn>=tn )
for (int i=1; i<n; i++)
Si = Si - dn;
else
place this process//将当前进程放置在第一个不满足Si>=1的阻塞队列中
}
void signal(S1, d1, S2, d2, ... , Sn, dn,){
for (int i=1; i<n; i++)
Si = Si + dn;
romove all the process waiting in the queue associated with Si into ready queue
}
信号量的应用
利用信号量实现进程互斥
semaphore S = 1; //初化信号量
P1 ( ) {
P1 process1
P(S); // 准备开始访问临界资源,加锁
// 进程P1的临界区
V(S); // 访问结束,解锁
P1 process2
}
P2() {
P2 process1
P(S); //准备开始访问临界资源,加锁
// 进程P2的临界区;
V(S); // 访问结束,解锁
P2 process2
}
利用信号量实现前趋关系
如S2 依赖 S1 则设置一个信号量P1=0, 在s2 开始前P(p1).在在S1结束时V(p1);
管程机制
管程:管程 (英语:Monitors,也称为监视器) 是一种程序结构,结构内的多个子程序对象或模块形成的多个工作线程互斥访问共享资源。这些共享资源一般是硬件设备或一群变量。管程实现了在一个时间点,最多只有一个线程在执行管程的某个子程序。与那些通过修改数据结构实现互斥访问的并发程序设计相比,管程实现很大程度上简化了程序设计。管程提供了一种机制,线程可以临时放弃互斥访问,等待某些条件得到满足后,重新获得执行权恢复它的互斥访问。
一个管程包含:
- 多个彼此可以交互并共享资源的线程
- 多个与资源使用有关的变量
- 一个互斥锁
- 一个用来避免竞态条件]的不变量
一个管程的程序在运行一个线程前会先获取互斥锁,直到完成线程或是线程等待某个条件被满足才会放弃互斥锁。若每个执行中的线程在放弃互斥锁之前都能保证不变量成立,则所有线程皆不会导致竞态条件成立。
生产者-消费者问题:
生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题,是一个多进程同步问题的经典案例。该问题描述了共享固定大小缓冲区的两个进程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。
要解决该问题,就必须让生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。通常采用进程间通信的方法解决该问题。如果解决方法不够完善,则容易出现死锁的情况。出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己。该问题也能被推广到多个生产者和消费者的情形。
哲学家进餐问题:
哲学家就餐问题可以这样表述,假设有五位哲学家围坐在一张圆形餐桌旁,做以下两件事情之一:吃饭,或者思考。吃东西的时候,他们就停止思考,思考的时候也停止吃东西。餐桌中间有一大碗意大利面,每两个哲学家之间有一只餐叉。因为用一只餐叉很难吃到意大利面,所以假设哲学家必须用两只餐叉吃东西。他们只能使用自己左右手边的那两只餐叉。
哲学家从来不交谈,这就很危险,可能产生死锁。
在实际的计算机问题中,缺乏餐叉可以类比为缺乏共享资源。例如,某个程序需要访问两个文件,当两个这样的程序各锁了一个文件,那它们都在等待对方解锁另一个文件,而这永远不会发生。
解决办法:仅当两只筷子都能取时才取;对筷子编号,先取编号小的;
读者-写者问题:
有读者和写者两组并发进程,共享一个文件,当两个或以上的读进程同时访问共享数据时不会产生副作用,但若某个写进程和其他进程(读进程或写进程)同时访问共享数据时则可能导致数据不一致的错误。因此要求:
①允许多个读者可以同时对文件执行读操作;
②只允许一个写者往文件中写信息;
③任一写者在完成写操作之前不允许其他读者或写者工作;
④写者执行写操作前,应让已有的读者和写者全部退出。
目前高级的通信机制归结为:共享存储机制系统,管道通信系统,消息传递系统,客户端-服务端系统。
进程所涉及到的一些系统调用
fork()
fork是一种创建自身行程副本的操作。用于创建一个新进程,格式:int fork()
, fork()返回-1错误表示fork出错:没有新进程被创建。如果fork成功,那么现在有两个进程。两者都从fork返回时开始执行main函数(返回0表示子进程,大于0 表示子进程的id值)。为了使进程执行不同的任务,程序必须基于fork的返回值决定其作为子进程或父进程执行某个分支,调用成功后,向父进程返回PID,向子进程返回0,即fork()被调用一次,但是返回了两次。
exec()
包括一系列的系统调用,可用于新程序的运行。fork()将父进程的上下文考本到新进程中,而exec()系列函数可以将一个可执行的二进制文件覆盖到新进程的用户级上下文的存储空间以上。如果exec()执行成功,调用进程将被覆盖,然后从新进程的入口开始执行,因此产生了一个新进程。exec()没有产生一个新进程,而是用新进程取代了原来的进程,调用没有返回数据。
wait()
用于等待子进程结束,如果子进程没有完成,父进程将会一直等待。wait()将调用进程挂起,直至子进程完成或收到中断信号为止,调用格式为:int wait(status)
status 为0时表示正常结束。
exit()
终止进程的执行,格式为void exit(status)
, Linux利用exit()来实现进程的自我终止,通常父进程在创建子进程时应在末尾安排一条exit()。
lock()
用于锁定文件的某些段或整个文件,调用格式为:int lock(files, functon, size)
, files是文件描述,function中1表示锁定,0表示解锁,size表示锁定或解锁的字节数。
进程通信的类型
共享存储系统(Shared-Memory System)
不同进程共享某些数据结构或者共享存储区,通过这些空间进行通信。共享存储机制未提供互斥和同步的措施需要自己设置。与其有关的系统调用:shmget()
//创建一个共享存储区, shmat()
//共享存储区的附接。 shmctl()
//对状态进行读取和修改,smedt()
//将共享存储区域指定的进程地址。
管道(pipe)通信系统
管道指连接一个读进程和一个写进程以实现它们之间通信的一个共享文件,又名pipe文件。管道机制必须提供互斥,同步和确定对方是否存在这三方面的协调能力。管道通信首创于UNIX系统,能有效地传送大量数据。
消息传递系统(Message passing system)
将通信数据放到格式化的消息中,并利用操作系统提供的一组通信命令再进程之间进行消息传递。此方式隐藏了通信实现的细节,降低了程序复杂度和错误率,成为引用最为广泛的一类进程间通信的机制。可分为直接通信方式(利用OS提供的原语发送消息), 间接通信方式(通过中间实体进行收发数据)。
消息是一个格式化的可变长的信息单元,通常包如消息的类型,大小,数据区的指针等信息。与其有关的系统调用:msgeget()
,msgsnd()
msgrec()
msgctl()
。
客户端-服务端系统(Client-Server system)
socket是一种操作系统提供的进程间通信机制。在操作系统中,通常会为应用程序提供一组应用程序接口(API),称为套接字接口(英语:socket API)。应用程序可以通过套接字接口,来使用网络套接字,以进行数据交换。
该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而程序员无需额外地为这个交互作用编程。如果涉及的软件采用面向对象编程,那么远程过程调用亦可称作远程调用或远程方法调用。
人们提出比进程更小的基本单位线程视图使用它来提高程序并发执行的程度。引入进程是为了使多个程序能够并发执行,引入线程是为了减少程序并发执行时所付出的时空开销。
线程的引入
1)进程的基本属性:可拥有资源的基本单位;可独立调度和分派的基本单位。
程序并发执行需要付出的开销:创建进程时分配的资源; 撤销时回收操作; 进程切换时需要消耗CPU时间;
在OS中引入线程,以线程为调度和分派的基本单位,可以有效的改善多处理机系统的性能。
进程与线程
对于操作系统来说,一个任务就是一个进程(Process),有些进程还不止同时干一件事,在一个进程内部,要同时干多件事,就需要同时运行多个“子任务”,这些“子任务”称为线程(Thread)。一个进程至少有一个线程。线程是独立调度和分派的基本单位。同一进程中的多条线程将共享该进程中的全部系统资源。
线程与进程的对比
线程的状态和线程控制块
与进程一样:执行,就绪,阻塞
线程控制块TCB
多线程OS中进程属性
线程的实现方式
不同的系统实现方式不同。如:用户级线程,内核支持线程。。。
创建,阻塞,撤销等操作都是在内核控件中实现的。在内核空中为每一个内核线程设置了一个线程控制块,当前大多数的OS都支持内核支持线程。
优点:内核能调度同一个进程中的多个线程并发执行;进程中的一个线程阻塞了,内核能够运行其他线程;数据结构和堆栈小,切换快开销小;
缺点:从线程之间切换时需要从用户态装换到和心态,系统开销大。
无需内核支持,在用户控件中实现,内核不知道用户级线程的存在。
优点:节省了模式切换的开销;不同的进程可以更具自己需要寻找调度算法;进程的实现与OS平台无关;
线程的实现
处理机调度算法的目标
1)共同目标:资源利用率,公平性,平衡性,策略强制执行。
2)批处理系统的目标:降低平均周转时间,提高系统吞吐量,提高处理机利用率。
3)分时系统目标:提高相应时间,提高均衡性。
4)实时系统目标:截止时间的保证,可预测性。
作业相关的概念
作业(job) :批处理系统中,作业是调入内存的基本单位。它包含了程序和数据,还配有一份作业说明书,系统根据所明书对程序进行控制。作业时批处理系统中调入内存的基本单位。
作业步(job step) : 作业中的相对独立的加工步骤。 一个典型的作业可以分为以下作业步:编译、链接装配、运行。
作业控制块(Job Control Block, JCB):多批道处理系统中为每个作业设置了一个作业控制块,作为作业在系统中的标志,包含作业标识,用户名称,用户账号,作业类型,作业状态,调度信息,资源需求等信息。
作业运行的三个阶段和三种状态:
收容阶段(后备状态):把作业输入到硬盘,建立放入作业后备队列。
运行阶段(运行状态):为作业分配资源和建立进程,并放入就绪队列。
完成阶段(完成状态)。回收资源,输出结果。
作业调度的主要任务
调度的主要任务是根据JCB中的信息,检查系统的资源是否满足作业需求,以及按照一定的调度算法,从外存的后备队列中选取某些作业调入内存,并为它们创建进程,分配资源。最后将新建的进程排在就绪队列中等待调度。作业调度又称为接纳调度,每次作业调度都需要做两个决定:接纳多少个作业,接纳哪些作业。
接纳多少个作业:装入更多的作用有利于提高CPU的利用率和系统吞吐量,但若作业太多导致中断剧烈增加从而增加系统的平均周转时间。
选择哪些作业调入系统取决于使用的调度算法,如:先来先服务算法,短作业优先算法,作业优先级的调度算法,响应比高者优先算法。
先来先服务(FCFS)和短作业优先(SJF)调度算法
先来先服务调度算法:按照作业到达的先后或者等待的时长作为优先度依据,不管作业需要执行的时间长短,一直运行到结束或堵塞,再将处理机分配给其他进程。单处理机中很少作为主调度算法,而是与其他算法结合使用。
短作业优先调度算法:以作业完成所需要的时长作为优先度依据,时间越短优先度越高,这种算法在实际的情况中占有很大的比例。缺点是对长作业非常不利以及无法保证紧急的作用及时得到处理。
优先级调度算法和高响应比优先调度算法
优先级调度算法(priority-scheduling algorithm, PSA):给作业设置一个优先度,更具作业的优先度来进行调度。这个优先度是基于作业的紧迫程度的,又外部赋予。
高响应比优先调度算法(Highest Response Ratio Next, HRRN):引入一个动态变化的优先级,这个优先级描述为:优先权=(等待时间+要求服务时间) / 要求服务时间。它既考虑了作业的等待时间,又考虑了运行时间,因此既照顾了短作业,又使得长作业无需等待太长。
进程调度是OS中必不可少的一种调度,三种类型的OS中都无不例外地使用了进程调度。它也是对系统性能影响最大的一种处理机调度。
主要任务:
保存处理机现场信息:如程序计数器,通用寄存器中的内容
按照某种算法取进程:从就绪队列中取一个进程,改变其状态并分配处理机资源
把处理机分配给进程:按照PCB的信息在处理器相应的寄存器中转入信息,并把处理机控制权赋予进程。
机制:
为了实现进程调度,应该包含排队器,分派器,上下文切换器三个部分。
排队器将就绪进程按照一定的策略排成一个或多个队列,以便调度进程能最快找到它。
分派器依据调度程序选定的进程,将其从就绪队列中取出并分配处理机资源。
上下文切换器负责在处理机进行切换时保存进程的上下文和恢复CPU现场。
调度方式:
非强占方式(Nonpreemptive Mode): 当处理机分配给某进程后,就一直让它运行下去,直至进程完成或阻塞才将处理机分配给其他进程。优点是实现简单,开销小,适合批处理系统,但不能用于分时系统。
强占方式(Preemptive Mode):更具某些原则,暂停正在执行的进程,将处理机分配给其他进程,从而确保了处理机能够更加公平地为所有进程提供服务。现代的OS广泛使用强占方式。
轮转调度算法
分时系统中最简单,最常用和非常公平的处理机分配方式,基于时间片的轮转调度(round robin, RR),将时间片平分给每个进程。
优先级调度算法
把处理机分配给就绪队列中优先级最高的进程。可以吧算法进一步分为非抢占式和抢占式优先级调度算法。该算法的关键是如何确定优先级,以及使用动态优先级还是静态优先级。
多队列调度算法
将就绪队列从一条改进成多条,按照进程的类型或性质等分配到不同的就绪队列,不同的就绪队列采取不同的调度算法。
多级反馈队列调度算法
不必事先知道各种进程所需的执行时间,可以较好地满足各种类型进程的需要。其机制为:设置多条优先级和时间片不同的就绪队列,优先级越高时间片越小(第一队列的优先级最高),新进程进入内存后放到第一队列(FCFS策略),一个时间片内未完成则放到第二队列末尾。处理机只在第1~i-1队列为空时才会调度第i队列的进程运行。
基于公平原则的调度算法
保证调度算法
保证调度算法对性能做出明确的保证,可以做到调度的公平性,它需要维护一个值(程序实际执行的处理时间和获得处理机时间之比),选择比率最小的进程并分配处理机给它,一直运行至超过最接近它的比率。
公平分享调度算法
分配给每个进程相同的处理机时间,对各个进程公平,但是对拥有进程数不同的用户不公平。
为保证系统的正常工作,实时调度必须满足实时任务对截止时间的要求。
实现实时调度的基本条件
实时调度算法的分类
最早截止时间优先EDF算法
根据任务的截止时间确定优先级,最早截至的任务排在队列的首部。
最低松弛度优先LLF算法
根据任务的紧急程度来赋予优先级。松弛值计算方式为:松弛度=必须完成的时间-需要运行的时间-当前时间。
优先级倒置
是指一种现象,高优先级的进程被低优先级的进程延迟或堵塞。
所谓死锁是指多个进程因竞争资源而造成的一种僵局,若无外力作用,这些进程都将无法向前推进。死锁定义为一组相互竞争资源或通信的进程间“永久”阻塞。死锁是永久性的,死锁问题无有效的通用解决方案。
资源问题
引起死锁的资源主要是临界资源。通常系统中拥有的不可剥夺资源,其数量不足或满足多个进程运行的需要,进程在运行过程中会因争夺资源而陷入僵局。只有对不可剥夺资源的竞争才可能产生死锁,对可剥夺资源的竞争是不会引起死锁的。
系统中的资源按照重用性可以分为可重用性资源和可消耗性资源。系统中的大多数资源为可重用性资源,进程对资源的请求通常通过系统调用来实现。
可把系统中的资源分为可抢占和不可抢占资源两类,打印机等属于不可抢占资源。可抢占性质与的竞争不会引发死锁。
计算机系统中的死锁
死锁一是源于多个进程对系统资源的争夺,包括对不可抢占性资源和消耗性资源的争夺,二是由于程序推进的顺序不当,如请求和释放资源的顺序不当。
死锁的定义
如果一组进程中的每一个进程都在等待仅有该组中其他进程才能引发的事件,那么该组进程数死锁的。
死锁的必要条件
产生死锁必须同时满足以下四个条件,只要其中任一个条件不成立,死锁就不会发生。
死锁的处理
为使系统不发生死锁,必须设法破坏产生死锁的四个必要条件之一,或者允许死锁产生,但当死锁发生时能检测出思索,并有能力实现恢复。
系统安全状态
指系统能按某种进程推进顺序,为每个进程分配其所需的资源,直至满足每个进程对资源的最大需求,是每个进程都可以顺序的完成。此时成P1P2P3。。为安全序列,如果系统无法找到一个安全序列,则称系统处于不安全状态。并非所有的不安全状态都是死锁状态,但当系统进入不安全状态后,便可能进入死锁状态;反之,只要系统处于安全状态,系统便可以避免进入死锁状态。
利用银行家算法避免死锁
银行家算法是最著名的死锁避免算法,思想是:把操作系统看作是银行家,操作系统管理的资源相当于银行家管理的资金,进程向操作系统请求分配资源相当于用户向银行家贷款。操作系统按照银行家制定的规则为进程分配资源,当进程首次申请资源时,要测试该进程对资源的最大需求量,如果系统现存的资源可以满足他的最大需求量,则按当前的申请量分配资源,否则就推迟分配。当进程在执行中继续申请资源时,先测试该进程已占用的资源数与本次申请的资源数之和是否超过了该进程对资源的最大需求量。若超过,则拒绝分配资源,若没有超过则再测试系统现存的资源能否满足该进程尚需的最大资源量,若能满足则按当前的申请量分配资源,否则也要推迟分配。
死锁的检测
可利用资源分配图来描述。用圆圈代表一个进程,用方框代表一类资源。由于一种类型的资源可能有很多个,用框中的一个点代表一类资源中的一个资源。从进程到资源的有向边叫请求边,表示该进程请申请一个单位的该类资源;从资源到进程的边叫做分配边,表示该类资源已经有一个资源被分配到了该进程。可以通过将资源分配图简化的方法来检测系统状态S是否为死锁状态。简化方法如下:
1)在资源分配图中,找出既不阻塞又不是孤点的进程Pi,消去它所有的请求边和分配边,使之成为孤立的节点。
2)进程Pi所释放的资源,可以唤醒某些因等待这些资源而阻塞的进程,原来的阻塞进程可能变为非阻塞进程。
死锁的解除
1)资源剥夺法。挂起某些思索进程,并抢占它的资源,将这些资源分配给其他的死锁进程。但应防止被挂起的进程长时间得不到资源时,而处于资源匮乏的状态。
2)进程撤销法。强制撤销一个或一部分进程并剥夺这些进程的资源。撤销的原则可以按进程的优先级和撤销进程代价的高低进行。
3)进程回退法。让一个或多个进程回退到足以回避死锁的地步,进程回退时资源释放资源而不是被剥夺。要求系统保持进程的历史信息,设置还原点。
存储器管理的对象主要是内存,对外存的管理方式与内存相似。几乎每条指令都涉及到存储器的访问,因此访问存储器的速度会明显影响处理机的速度。内存管理是操作系统设计中最重要和最复杂的内容之一。操作系统对内存的划分和动态分配,就是内存管理的概念。
多层存储结构和存储系统
多层结构
可以将存储器分成寄存器、高速缓存、主存、磁盘缓存、固定磁盘、可移动存储介质几个层次。寄存器,主存、缓存等数据掉电后信息不复存在,其他的介质属于设备管理的管辖范畴。
可执行存储器
寄存器和主存储器又称为可执行存储器,他们被计算机访问的机制不同,进程可以使用一条指令访问数据。辅存的访问则通过I/O设备实现,因此耗费的时间相差很大。
主存储器与寄存器
主存储器
又称内存或主存,可执行存储器。处理机从主存储器中获取指令然后放到指令寄存器中。主存的访问速度远低于CPU执行指令的速度,为缓和这一矛盾,在计算机系统中引入了寄存器和高速缓存。
寄存器
寄存器与CPU有这相同的速度,故寄存器的访问速度最快,完全能与CPU协调工作,但是价格十分昂贵。
高速缓存和磁盘寄存器
高速缓存
主要用于备份主存中比较常用的数据,以减少处理机对主存的访问次数,从而提高程序的执行速度。在计算机系统中许多地方都设有高速缓存。
磁盘寄存器
主要用于存放频繁使用的一部分磁盘数据和信息以减少对磁盘的访问次数。它本身不是一种实际存在的存储器,而是利用主存中部分存储空间暂时存放从磁盘中读取的信息。主存也可以看作赋存的高速缓存。因此辅存中的数据必须先经过主存才能被使用,反之数据也必须先经过主存才能被输出到辅存。
在进行具体的内存管理之前,需要了解进程运行的基本原理和要求。创建进程首先要将程序和数据装入内存。将用户原程序变成可在内存中执行的程序,通常需要以下几个步骤。编译,由编译程序将用户源代码编译成若干个目标模块。 链接,由链接程序将编译后形成的一组目标模块,以及所需库函数链接,形成完整的装入模块。装入,由装入程序将装入模块装入内存。
程序的连接
程序的链接有以下三种方式:
程序的装入
内存的装入模块再装入内存时,同样有以下三种方式:
绝对装入。在编译时,如果知道程序将驻留在内存的某个位置,编译程序将产生绝对地址的目标代码。绝对装入程序按照装入模块的地址,将程序和数据装入内存。装入模块被装入内存后,由于程序中的逻辑地址与实际地址完全相同,故不需对程序和数据的地址进行修改。绝对装入方式只适用于单道程序环境。另外,程序中所使用的绝对地址,可在编译或汇编时给出,也可由程序员直接赋予。
可重定位装入。在多道程序环境下,多个目标模块的起始地址通常都是从0开始,程序中的其他地址都是相对于起始地址的,此时应采用可重定位装入方式。根据内存的当前情况,将装入模块装入到内存的适当位置。装入时对目标程序中指令和数据的修改过程称为重定位,地址变换通常是装入时一次完成,所以成为静态重定位。其特点是在一个作业装入内存时,必须分配器要求的全部内存空间,如果没有足够的内存,就不能装入,此外一旦作业进入内存后,在整个运行期间,不能在内存中移动,也不能再申请内存空间。
动态运行时装入,也成为动态重定位,程序在内存中如果发生移动,就需要采用动态的装入方式。动态运行时的装入程序在把装入模块装入内存后,并不立即把装入模块中的相对地址转换为绝对地址,而是把这种地址转换推迟到程序真正要执行时才进行。因此,装入内存后的所有地址均为相对地址,这种方式需要一个重定位寄存器的支持。其特点是可以将程序分配到不连续的存储区中;在程序运行之前可以只装入它的部分代码即可运行,然后在程序运行期间,根据需要动态申请分配内存;便于程序段的共享,可以向用户提供一个比存储空间大得多的地址空间。其特点是可以将程序分配到不连续的存储区中;在程序运行之前可以只装入它的部分代码即可运行,然后在程序运行期间,根据需要动态申请分配内存;便于程序段的共享,可以向用户提供一个比存储空间大得多的地址空间。
编译后,一个目标程序所限定的地址范围称为改程序的逻辑地址空间。编译程序在对一个源程序进行编译时,总是从0号单元开始为期分配地址,地址空间中的所有地址都是相对起始地址0的,因而逻辑地址也称为相对地址。用户程序和程序员只需要知道逻辑地址,而内存管理的具体机制则是透明的,这些只有系统编程人员才会涉及。不同进程可以有相同的逻辑地址,因为这些相同的逻辑地址可以映射到主存的不同位置。
物理地址空间实质内存中物理单位的集合,它是地址转换的最终地址,进程在运行时执行指令和访问数据最后都要通过物理地址来存取主存。当装入程序将可执行代码装入内存时,必须通过地址转换将逻辑地址转换成物理地址,这个过程称为地址重定位。
内存分配前,需要保护操作系统不受用户进程的影响,同时保护用户进程不受其他用户进程的影响。通过采用重定位寄存器和界地址寄存器来实现这种保护。重定位寄存器含最小的物理地址值,界地址寄存器含逻辑地址值。每个逻辑地址值必须小于界地址寄存器。内存管理机构动态地将逻辑地址加上重定位寄存器的值后映射成物理地址,再送交内存单元。
当CPU调度程序选择进程执行时,派遣程序会初始化重定位寄存器和界地址寄存器。每个地址都需要与寄存器进行核对,可以保证操作系统和其他用户程序及数据不被该进程运行所影响。
连续分配方式,是指为一个用户程序分配一个连续的内存空间。它主要包括单一连续分配、固定分区分配和动态分区分配。
单一连续分配
在单道程序环境下,存储器管理的方式是把内存分为系统区和用户区,系统区仅提供给操作系统使用,通常在低地址部分;用户区是为用户提供的除系统外的内存空间。在用户区内存中,仅装有一道用户程序,即整个内存的用户空间由该程序独占。这种方式的优点是简单、无外部碎片,可以采用覆盖技术,不需要额外的技术支持。缺点是只能用于单用户、单任务的操作系统中,有内部碎片,存储器的利用率极低。
固定分区分配
固定分区分配是最简单的一种多道程序存储管理方式,它将内存用户空间划分为若干个固定大小的区域,每个分区只装入一道作业。当有空闲分区时,便可以再从外存的后备队列中选择适当大小的作业装入该分区。如此循环。固定分区方式是最早出现的、可用于多道程序系统的存储管理方式。固定分区分配在划分分区时,有两种不同的方法:
为了便于内存分配,通常将分区按大小排队,并为之建立一张分区使用表,其中个表项包括每个分区的起始地址、大小及状态。当有用户程序要装入时,便检索该表,已找到合适的分区给与分配并将其状态置为“已分配“。未找到合适分区则拒绝为该用户程序分配内存。
这种分区方式存在两个问题:一个程序可能太大而放不进任何一个分区中,这是用户不得不使用覆盖技术来使用内存空间;二是主存利用率低,当程序小于固定分区大小时,也占用了一个完整的内存分区空间,这样分区内部有空间浪费。这种现象成为内部碎片。
固定分区可用于多道程序设计最简单的存储分配,但不能实现多进程共享一个主存区,所以存储空间利用率低。固定分区分配很少用于现在通用的计算机,但在某些用于控制多个相同对象的控制系统中仍发挥着一定的作用。
动态分区分配
动态分区分配又称为可变分区分配,是一种动态划分内存的分区方法。这种分区方法预先将内存划分,而是在进程装入内存时,根据进程的大小动态的建立分区,并使分区的大小正好适合进程的需要。因此系统中分区的大小和数目是可变的。动态分区在开始分配时是很好的,但是之后会导致内存中出现许多小的内存块。随着时间的推移,内存中会产生越来越多的碎片,内存的利用率随之下降。这种现象称之为外部碎片现象,指在所有分区外的存储空间会变成越来越多的碎片,这与固定分区中的内部碎片正好相对。克服外部碎片可以通过紧凑技术来解决,就是操作系统不时地对进程进行移动和整理。但是这需要动态定位的支持,且相对费时。紧凑的过程实际上类似于windows系统中的磁盘整理程序,只不过后者是对外存空间的紧凑。
基于顺序搜索的动态分区分配算法
在进程装入或换入主存时。如果内存中有多个足够大的空闲块,操作系统必须确定分配那个内存块给进程使用,这就是动态分区的分配策略,主要有以下几种算法:
首次适应算法(First Fit, FF)
空闲分区以地址递增的次序链接。分配内存时顺序查找,找到大小能满足要求的第一个空闲分区。缺点是会产生很多碎片。
循环首次适应算法 (Next Fit NF)
从上次划出的空间分区开始查找,知道找到一个能满足要求的空闲分区,从中划出一块与请求大小相等的内存空间分配给作业。该算法使内存中的空闲分区分布更加均匀,从而减少了查找空闲分区时的开销,但是这样会缺乏大的空闲分区。
最佳适应算法(Best Fit, BF)
最佳指每次为作业分配内存时,总能满足要求、又是最小的空闲分区分配给作业。该算法将空闲分区按容量递增形成分区链,找到第一个能满足要求的空闲分区。缺点:会留下很多难以利用的碎片。
最坏适应算法 (Worst Fit, WF)
有称最大适应算法,空闲分区以容量递减次序链接。找到第一个能满足要求的空闲分区,也就是挑选最大的分区。优点是使得剩下的空闲区不至于太小,产生碎片的可能性最小,对中小作业有利。
基于索引搜索的动态分配算法
动态可重新位分区分配
虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存物理内存/2502263)碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。目前,大多数操作系统都使用了虚拟内存,如Windows家族的“虚拟内存”;Linux的“交换空间”等。分页管理提供1维的地址结构,分段管理提供2维的地址结构。
常规存储管理方式的特征
局部性原理
局部性原理是指CPU访问存储器时,无论是存取指令还是存取数据,所访问的存储单元都趋于聚集在一个较小的连续区域中。三种不同类型的局部性:
时间局部性(Temporal Locality):如果一个信息项正在被访问,那么在近期它很可能还会被再次访问。
程序循环、堆栈等是产生时间局部性的原因。
空间局部性(Spatial Locality):在最近的将来将用到的信息很可能与现在正在使用的信息在空间地址上是临近的。
顺序局部性(Order Locality):在典型程序中,除转移类指令外,大部分指令是顺序进行的。顺序执行和非顺序执行的比例大致是5:1。此外,对大型数组访问也是顺序的。
指令的顺序执行、数组的连续存放等是产生顺序局部性的原因。
虚拟存储器的基本工作原理
根据局部性原理,在程序装入时,不需要将其全部读入到内存,而只需将当前需要执行的部分页或段读入到内存,就可让程序开始执行。
在程序执行过程中,如果需执行的指令或访问的数据尚未在内存(称为缺页或缺段) ,则由处理器通知操作系统将相应的页或段调入到内存,然后继续执行程序。 (请求调入功能)
另一方面,操作系统将内存中暂时不使用的页或段调出保存在外存上,从而腾出空间存放将要装入的程序以及将要调入的页或段。 (置换功能)
虚拟存储器的定义
具有请求调入功能和置换功能,能从逻辑上对内存容量加以扩充的一种存储器系统。
虚拟存储量的扩大是以牺牲 CPU 工作时间以及内外存交换时间为代价。
虚拟存储器的容量取决于主存与辅存的容量,最大容量是由计算机的地址结构决定。如 32 位机器,虚拟存储器的最大容量就是 4G,再大CPU 无法直接访问。
虚拟存储器的实现方法:请求分页、请求分段、请求段页式。
虚拟存储器的特征
多次性:作业被分成多次调入内存运行。正是由于多次性,虚拟存储器才具备了逻辑上扩大内存的功能。多次性是虚拟存储器最重要的特征,其它任何存储器不具备这个特征。
对换性:允许在作业运行过程中进行换进、换出。换进、换出可提高内存利用率。
虚拟性:指能够从逻辑上扩充内存容量,使用户所看到的内存容量远大于实际内存容量。虚拟性是实现虚拟存储器最重要的目标。虚拟性以多次性和对换性为基础,而多次性和对换性必须以离散分配为基础。
虚拟存储器的实现方法
虚拟存储器的实现,毫无例外地都建立在离散分配存储管理方式的基础上。目前所有的虚拟存储器都采用分页请求系统或请求分段系统来实现。
分页请求系统
这是在基本分页系统的基础上,增加了请求调页功能和页面置换功能所形成的页式虚拟存储系统。它允许只装入少数页面的程序(及数据),便启动运行。以后再通过调页功能及页面置换功能,陆续地把即将要运行的页面调入内存,同时把暂不运行的页面换出到外存上。置换时以页面为单位。为了能实现请求调页和置换功能,系统必须提供必要的硬件支持和相应的软件。
硬件支持–主要的硬件支持有:
- 请求分页的页表机制,它是在纯分页的页表机制上增加若干项**而形成的,作为请求分页的数据结构。
- 缺页中断机构,即每当用户程序要访问的页面尚未调入内存时,便产生一缺页中断,以请求OS将所缺的页调入内存。
- 地址变换机构,它同样是在纯分页地址变换机构的基础上发展形成的。
实现请求分页的软件:
这里包括有用于实现请求调页的软件和实现页面置换的软件。它们在硬件的支持下,将程序正在运行时所需的页面(尚未在内存中的)调入内存,再将内存中暂时不用的页面从内存置换到磁盘上。
请求分段系统
这是在基本分段系统的基础上,增加了请求调段及分段置换功能后形成的段式虚拟存储系统。
它允许只装入少数段(而非所有的段)的用户程序和数据,即可启动运行。
以后再通过调段功能和段的置换功能将暂不运行的段调出,同时调入即将运行的段。置换是以段为单位进行的。为了实现请求分段,系统同样需要必要的硬件支持。一般需要下列支持:
- 请求分段的段表机制。这是在纯分段的段表机制基础上增加若干项而形成的。
- 缺段中断机构。每当用户程序所要访问的段尚未调入内存时,产生一个缺段中断,请求OS将所缺的段调入内存。
- 地址变换机构。
与请求调页相似,实现请求调段和段的置换功能也需得到相应的软件支持。
请求分页系统在实现上比请求分段系统简单,是目前最常用的一种实现虚拟存储器的方式。
硬件支持:
计算机系统除了要求一定容量的内存和外存外,还需要有请求页表制、缺页中断机构以及地址变换机构。
请求页表机制
请求页表是请求分页系统中需要的和主要的数据结构。其基本作用仍然是将用户空间中的逻辑地址变换为内存空间中的物理地址。由于只将应用程序的一部分调入内存,还有一部分仍在盘上,故需在页表中再增加若干项,供程序(数据)在换进、换出时参考。
在请求分页系统中的每个页表项如下所示:
页号 | 物理块号 | 状态位P | 访问字段A | 修改位M | 外存地址 |
---|---|---|---|---|---|
用于指示该页是否已调入内存,供程序访问时参考。 | 用于记录本页在一段时间内被访问的次数,或记录本页最近已有多长时间未被访问,供选择换出页面时参考。 | 表示该页在调入内存后是否被修改过。供置换页面时参考 | 用于指出该页在外存上的地址,通常是物理块号,供调入该页时参考。 |
缺页中断机制
在请求分页系统中,每当所要访问的页面不在内存中时,便产生一次缺页中断,请求OS将所缺之页调入内存。缺页中断作为中断,同样需要经历诸如保护CPU现场、分析中断原因、转入缺页中断处理程序进行处理、恢复CPU现场等几个步骤。但缺页中断又是一种特殊的中断,它与一般的中断相比,有着明显的区别,主要表现在下面两个方面:
地址变换机制
请求分页系统中的地址变换机构,是在分页系统地址变换机构的基础上,为实现虚拟存储器而增加了某些功能而形成的,如产生和处理缺页中断,以及从内存中换出一页的功能等等。在进行地址变换时,首先去检索快表,试图从中找出所要访问的页。若找到,便修改页表项中的访问位。对于写指令,还需将修改位置成“1”,然后利用页表项中给出的物理块号和页内地址形成物理地址。地址变换过程到此结束。如果在快表中未找到该页的页表项时,应到内存中去查找页表,再根据找到的页表项中的状态位P,了解该页是否已调入内存。若该页已调入内存,这时应将此页的页表项写入快表,当快表已满时,应先调出按某种算法所确定的页的页表项;然后再写入该页的页表项。若该页尚未调入内存,这时应产生缺页中断,请求OS从外存把该页调入内存。
请求分页中的内存分配
最小物理块数的确定
最小物理块数指能保证进程正常运行所需的最小的物理块数,最小物理块数与计算机的硬件结构有关,取决于指令的格式、功能和寻址方式。
采用直接寻址方式,所需的最少物理块数为 2。一块是用于存放指令,另一块用于存放数据。
间接寻址时,至少要求有三个物理块。 (间接寻址中一些物理块放的是其它物理块的块号)
内存分配策略
在请求分页系统中,可采取两种内存分配策略:固定和可变分配策略,在进行置换时,也可采取两种策略:全局置换和局部置换。于是组合出3钟适合用的策略。
固定分配局部置换
为每个进程分配固定数目 n 的物理块,在整个运行中都不改变。如出现缺页则从该进程的页面中置换一页。每个进程分配多少个物理块难以确定。若太少,会频繁地出现缺页中断,降低了系统的吞吐量。
若太多,内存中驻留的进程数目减少,可能造成 CPU空闲或其它资源空闲的情况。
可变分配局部置换
为每个进程分配一定数目的物理块,但 OS 自留一空闲块队列,若发现缺页,则从空闲块队列中分配一空闲块与该进程,并调入缺页于其中。当空闲块队列用完时,OS 才从内存中任选择一页置换。
物理块分配算法
为每个进程分配一定数目的物理块,若发现缺页,则从该进程的页面中置换一页,不会影响其它进程的运行。根据进程缺页率高低,则可增加或减少分配给该进程的物理块。
物理块分配算法
在采用固定分配策略时,可采用以下几种算法:
页面调入策略
为使进程能够正常运行,必须事先将要执行的那部分层序和数据所在的页面调入内存。因此有何时调入,何处调入,如何调入的问题:
何时调入
可采取预调页策略和请求调页策略。预调页:将预计在不久之后便会被访问的页面预先调入内存。进程的页一般存放在外存的一个连续区域中。一次调入若干个相邻的页会比一次调入一页更高效。但如果调入的一批页面中的大多数都未被访问,则浪费了内存。请求调页策略:当进程在运行中发生缺页时,就立即提出请求,由系统将缺页调入内存。但这种策略每次仅调入一页,须花费较大的系统开销,增加了启动磁盘 I/O 的频率。
何处调入
在请求分页系统中,外存分成了按离散分配方式存放文件的文件区和按连续分配方式存放对换页的对换区。进程发出缺页请求时,从何处将缺页调入内存呢?对换区:如果系统有足够的对换区空间,运行前可将与进程相关的文件从文件区复制至对换区,以后缺页时全部从对换区调页。文件区:如果系统没有足够的对换区空间,凡是不会被修改的文件,直接从文件区调页,不必回写(换出) 。对可能会修改的文件第一次直接从文件区调页,换出时换至对换区,以后从对换区调页。UNIX 方式:凡未运行过的页面均从文件区调页,运行过的页面和换出的页面均从对换区调页。
调入过程
缺页率
缺页率:访问页面失败的次数除以访问页面的总次数。影响缺页率的常见因素有:页面大小(反比)、分配到的物理块数目(反比),页面置换算法,程序固有特征 。
地址映射过程中,若在页面中发现所要访问的页面不再内存中,则产生缺页中断。当发生缺页中断时操作系统必须在内存选择一个页面将其移出内存,以便为即将调入的页面让出空间。而用来选择淘汰哪一页的规则叫做页面置换算法。常见的置换算法有:
最佳置换算法(OPT)(理想置换算法)
这是一种理想情况下的页面置换算法,但实际上是不可能实现的。该算法的基本思想是:发生缺页时,有些页面在内存中,其中有一页将很快被访问(也包含紧接着的下一条指令的那页),而其他页面则可能要到10、100或者1000条指令后才会被访问,每个页面都可以用在该页面首次被访问前所要执行的指令数进行标记。最佳页面置换算法只是简单地规定:标记最大的页应该被置换。这个算法唯一的一个问题就是它无法实现。当缺页发生时,操作系统无法知道各个页面下一次是在什么时候被访问。虽然这个算法不可能实现,但是最佳页面置换算法可以用于对可实现算法的性能进行衡量比较。
先进先出置换算法(FIFO)
最简单的页面置换算法是先入先出(FIFO)法。这种算法的实质是,总是选择在主存中停留时间最长(即最老)的一页置换,即先进入内存的页,先退出内存。理由是:最早调入内存的页,其不再被使用的可能性比刚调入内存的可能性大。建立一个FIFO队列,收容所有在内存中的页。被置换页面总是在队列头上进行。当一个页面被放入内存时,就把它插在队尾上。这种算法只是在按线性顺序访问地址空间时才是理想的,否则效率不高。因为那些常被访问的页,往往在主存中也停留得最久,结果它们因变“老”而不得不被置换出去。FIFO的另一个缺点是,它有一种异常现象,即在增加存储块的情况下,反而使缺页中断率增加了。当然,导致这种异常现象的页面走向实际上是很少见的。
最近最久未使用(LRU)算法
FIFO算法和OPT算法之间的主要差别是,FIFO算法利用页面进入内存后的时间长短作为置换依据,而OPT算法的依据是将来使用页面的时间。如果以最近的过去作为不久将来的近似,那么就可以把过去最长一段时间里不曾被使用的页面置换掉。它的实质是,当需要置换一页时,选择在最近一段时间里最久没有使用过的页面予以置换
。这种算法就称为最久未使用算法(Least Recently Used,LRU)。LRU算法是与每个页面最后使用的时间有关的。当必须置换一个页面时,LRU算法选择过去一段时间里最久未被使用的页面。LRU算法是经常采用的页面置换算法,并被认为是相当好的,但是存在如何实现它的问题。LRU算法需要实际硬件的支持。其问题是怎么确定最后使用时间的顺序,对此有两种可行的办法:
1.计数器。最简单的情况是使每个页表项对应一个使用时间字段,并给CPU增加一个逻辑时钟或计数器。每次存储访问,该时钟都加1。每当访问一个页面时,时钟寄存器的内容就被复制到相应页表项的使用时间字段中。这样我们就可以始终保留着每个页面最后访问的“时间”。在置换页面时,选择该时间值最小的页面。这样做,不仅要查页表,而且当页表改变时(因CPU调度)要维护这个页表中的时间,还要考虑到时钟值溢出的问题。
2.栈。用一个栈保留页号。每当访问一个页面时,就把它从栈中取出放在栈顶上。这样一来,栈顶总是放有目前使用最多的页,而栈底放着目前最少使用的页。由于要从栈的中间移走一项,所以要用具有头尾指针的双向链连起来。在最坏的情况下,移走一页并把它放在栈顶上需要改动6个指针。每次修改都要有开销,但需要置换哪个页面却可直接得到,用不着查找,因为尾指针指向栈底,其中有被置换页。
因实现LRU算法必须有大量硬件支持,还需要一定的软件开销。所以实际实现的都是一种简单有效的LRU近似算法。
一种LRU近似算法是最近未使用算法(Not Recently Used,NUR)。它在存储分块表的每一表项中增加一个引用位,操作系统定期地将它们置为0。当某一页被访问时,由硬件将该位置1。过一段时间后,通过检查这些位可以确定哪些页使用过,哪些页自上次置0后还未使用过。就可把该位是0的页淘汰出去,因为在最近一段时间里它未被访问过。
Clock置换算法(LRU算法的近似实现)
最少使用(LFU)置换算法
在采用最少使用置换算法时,应为在内存中的每个页面设置一个移位寄存器,用来记录该页面被访问的频率。该置换算法选择在最近时期使用最少的页面作为淘汰页。由于存储器具有较高的访问速度,例如100 ns,在1 ms时间内可能对某页面连续访问成千上万次,因此,通常不能直接利用计数器来记录某页被访问的次数,而是采用移位寄存器方式。每次访问某页时,便将该移位寄存器的最高位置1,再每隔一定时间(例如100 ns)右移一次。这样,在最近一段时间使用最少的页面将是∑Ri最小的页。LFU置换算法的页面访问图与LRU置换算法的访问图完全相同;或者说,利用这样一套硬件既可实现LRU算法,又可实现LFU算法。应该指出,LFU算法并不能真正反映出页面的使用情况,因为在每一时间间隔内,只是用寄存器的一位来记录页的使用情况,因此,访问一次和访问10 000次是等效的。
由于虚拟存储器系统能从逻辑上扩大内存,人们希望在系统中能运行更多的进程,即增加多道程序度,以提高处理机的利用率。如果多道程度过高,页面在内存与外存之间频繁调度,以至于调度页面所需时间比进程实际运行的时间还多,此时系统效率急剧下降,甚至导致系统崩溃。这种现象称为颠簸或抖动(thrashing)。抖动的后果:缺页率急剧增加,内存有效存取时间加长,系统吞吐量骤减(趋近于零) ;系统已基本不能完成什么任务。抖动产生原因:同时运行的进程数过多,进程频繁访问的页面数高于可用的物理块数,造成进程运行时频繁缺页。CPU 利用率太低时,调度程序就会增加多道程序度,将新进程引入系统中,反而进一步导致处理机利用率的下降。操作系统需要一种降低缺页率、防止抖动的内存管理方法:工作集策略
工作集
工作集是指在某段时间间隔 ∆ 里,进程实际要访问的页面的集合。
工作集(或驻留集)是指在某段时间间隔内,进程要访问的页面集合。经常被使用的页面需要在工作集中,而长期不被使用的页面要从工作集中被丢弃。为了防止系统出现抖动现象,需要选择合适的工作集大小。
工作集模型的原理是:让操作系统跟踪每个进程的工作集,并为进程分配大于其工作集的物理块。如果还有空闲物理块,则可以再调一个进程到内存以增加多道程序数。如果所有工作集之和增加以至于超过了可用物理块的总数,那么操作系统会暂停一个进程,将其页面调出并且将其物理块分配给其他进程,防止出现抖动现象。
正确选择工作集的大小,对存储器的利用率和系统吞吐量的提嵩,都将产生重要影响。
抖动的预防方法
采取局部置换策略
仅允许进程在自身范围内进行置换。即使发生抖动,也可以把影响限制在较小范围内。
把工作集算法融合到处理机调度中
利用“L=S”准则调节缺页率
挂起若干进程
当多道程序度偏高,已影响到处理机的利用率时,为了防止发生抖动,系统必须减少多道程序的数目。把某些低优先级的进程挂起,从而腾出内存空间。
分段式虚拟存储器系统,是以分段为单位进行换入,换出的,与分页式虚拟存储器系统的原理和所需硬件支持十分相似。在请求分段存储管理系统中,作业运行之前,只要求将当前需要的若干个分段装入内存,便可启动作业运行。引入分段存储管理方式,主要是为了满足用户和程序员的下述一系列需要:方便编程,信息共享,信息保护,动态增长,动态链接。
硬件支持
请求段表机制
段名 | 段长 | 段基址 | 存取方式 | 访问字段A | 修改位P | 增补位 | 外存始址 | |
---|---|---|---|---|---|---|---|---|
只执行,只读,允许读写 | 记录访问的频繁程度 | 是否被修改过 | 是否已调入内存 | 是否做过动态增长 | 外存中的起始地址 |
缺段中断机构
地址变换机构
分段的共享和保护
共享段的分配与回收
共享段的分配:
当第一个使用共享段的进程提出请求时,由系统为该共享段分配一物理区,并调入该共享段,同时修改相应的段表(该段的内存地址)和共享段表,把 count 置为 1。当其它进程需要调用此段时,不需再调入,只需修改相应的段表和共享段表,再执行 count :=count+1 操作。
共享段的回收:
当共享共享段的某进程不再使用该共享段时,修改相应的段表和共享段表,执行 count :=count-1 操作。当最后一共享此段的进程也不再需要此段时,则系统回收此共享段的物理区,同时修改共享段表(删除该表项) 。
I/O系统的基本功能
隐藏物理细节
通过对设备加以抽象,隐藏物理设备的实现细节,仅向上层提供少量的读写命令。
与设备的无关性
做到即插即用。
提高处理机和I/O设备的利用率
尽量提高响应速度和运行设备时处理机的干预时间。
对I/O设备进行控制
对I/O设备有几种常见的控制方式:
轮询的可编程I/O方式
中断的可编程I/O方式
直接存储器访问方式
I/O 通道方式
对于打印机,键盘等设备,其传输数据的基本单位是字节,采用方式1
对于磁盘,光盘,基本单位是块,采用方式3
确保设备的正确共享
根据共享属性可以将设备分成:独占设备(进程应该互斥地访问这些设备,如打印机),共享设备。
错误处理
从处理机的角度可以将错误分为临时性错误和持久性错误。对于临时性错误可以通过重新操作来处理,只有发现持久性错误时才向上层报告。对于设备错误的处理应该尽可能在硬件层面,只有低层无法处理才向上层报告,请求高层软件解决。
I/O系统的层次结构和模型
将IO需要完成的功能组织成一系列的层次结构,每一层利用下一层提供的服务。每层完成的是一个子功能,并向上层提供服务接口。这些特征基本上都是层次系统通用的特性。
I/O软件层次结构
通常将I/O软件组织成四个层次。
- 用户层IO软件
实现用户交互的接口,可又用户直接调用。
- 设备独立性软件
用于实现用户程序与设备驱动器的统一接口、设备命令、设备保护,以及设备分配与释放等,同时也为设备管理和数据传送提供必要的存储空间。
- 设备驱动程序
硬件相关,实现OS对设备发出的操作指令,驱动IO设备工作。每一类设备有一个设备驱动程序。
- 中断处理程序
用于保存被中断进程的CPU环境,转入相应的中断处理程序进行处理,处理完毕再恢复被中断进程的现场后,返回被中断的进程。
I/O系统分层
I/O系统接口
块设备接口
块设备指数据的存取以块为单位的设备,典型的设备是磁盘。基本特点一是传输速率高,二是可寻址。
流设备接口
又称为字符设备接口,数据的存取以字符为单位,如打印机和键盘,不能寻址。大多数流设备都是独占设备。
网络通信接口
I/O设备
IO设备管理是操作系统设计中最凌乱也最具挑战性的部分。由于它包含了很多领域的不同设备以及与设备相关的应用程序,因此很难有一个通用且一直的设计方案。所以在理解设备管理之前,应该先了解具体的IO设备类型。
按使用特性可以分为一下类型:
1)人机交互类外部设备,又称慢速IO设备,用于桶计算机用户之间交互的设备,如打印机、显示器、鼠标、键盘等。这类设备数据交换速度相对较慢,通常是以字节为单位进行数据交换。
2)存储设备,通常以多字节组成的块为单位进行数据交换。
3)网络通信设备,如各种网络接口、调制解调器等。网络通信设备在使用和管理上与前两者设备有很大的不同。
按信息交换的单位分类:
1)块设备
2)字符设备
三种不同类型的使用方式:
1)独占式使用设备
2)分时式共享使用设备
设备与控制器之间的接口
IO应用接口的具体实现方式是:先把IO设备划分为若干种类的通用类型;然后对每一种类型提供一组标准函数来访问,这里的标准函数就是接口;为每个IO设备提供各自的设备驱动程序,各种设备间的差异就体现在设备驱动程序的不同之中,而对于访问这些设备的接口却是按照该设备分数的类型而统一。
划分IO设备所属的通用类型的依据:
- 字符设备还是块设备。
- 顺序访问还是随机访问。
- IO传输是同步还是异步。
- 共享设备还是独占设备。
- 操作速度的高低。
- 访问模式是读写、只读还是只写
设备控制器
设备控制器是CPU与设备之间的接口,接收命令去控制设备工作。设备控制器是一个可编址的设备,若控制器可连接多个设备,则它有多个地址,每个地址对应一个设备。
IO设备通常包括一个机械部件和一个电子部件。为了达到设计的模块性和通用性,一般将其分开。电子部件称为设备控制器(或适配器),在个人计算机中,通常是一块插入主板扩充槽的印制电路板;机械部件即设备本身。
由于具体的设备操作涉及硬件接口,且不同的设备有不同的硬件特性和参数,所以这些复杂的操作交由操作系统用户编写程序来操作是不实际的。引入控制器后,系统可以通过几个简单的参数完成对控制器的操作,而具体的硬件操作则由控制器调用相应的设备接口完成。设备控制器的引入大大简化了操作系统的设计,特别是有利于计算机系统和操作系统对各类控制器和设备的兼容;同时也实现了主存和设备之间的数据传输操作,使CPU从繁重的设备控制操作中解放出来。
设备控制器通过寄存器与CPU通信,在某些计算机上,这些寄存器占用内存地址的一部分,称为内存映像IO;另一些计算机则采用IO专用地址,寄存器独立编址。操作系统通过想控制器寄存器写命令字来执行IO功能。控制器收到一条命令后,CPU可以转向进行其他工作,而让设备控制器自行完成具体IO操作。当命令执行完毕后,控制器发出一个中断信号,操作系统重新获得CPU的控制权并检查执行结果,此时,CPU仍旧是从控制器寄存器中读取信息来获得执行结果和设备的状态信息。
设备控制器的主要功能为:
- 接收和识别CPU或通道发来的命令
- 实现数据交换。(通常设置了数据寄存器来暂存CPU发来的数据)
- 发现和记录设备及自身的状态信息
- 设备地址识别
设备控制器的组成
- CPU与控制器的接口:相当于中介。
- I/O逻辑:负责接收和处理CPU发出的命令。
- 控制器与设备的接口:一个控制器可能负责多个设备。
内存映像I/O
几乎每一种外设都是通过读写设备上的寄存器来进行的。外设寄存器也称为“I/O端口”,通常包括:控制寄存器、状态寄存器和数据寄存器三大类,而且一个外设的寄存器通常被连续地编址。CPU对外设IO端口物理地址的编址方式有两种:一种是I/O映射方式(I/O-mapped),另一种是内存映射方式(Memory-mapped)。而具体采用哪一种则取决于CPU的体系结构。
有些体系结构的CPU通常只实现一个物理地址空间(RAM)。在这种情况下,外设I/O端口的物理地址就被映射到CPU的单一物理地址空间中,而成为内存的一部分。此时,CPU可以象访问一个内存单元那样访问外设I/O端口,而不需要设立专门的外设I/O指令。这就是所谓的“内存映射方式”(Memory-mapped)。
而另外一些体系结构的CPU则为外设专门实现了一个单独地地址空间,称为“I/O地址空间”或者“I/O端口空间”。这是一个与CPU地RAM物理地址空间不同的地址空间,所有外设的I/O端口均在这一空间中进行编址。CPU通过设立专门的I/O指令(如X86的IN和OUT指令)来访问这一空间中的地址单元(也即I/O端口)。这就是所谓的“I/O映射方式”(I/O-mapped)。与RAM物理地址空间相比,I/O地址空间通常都比较小,这是“I/O映射方式”的一个主要缺点。
I/O通道
在CPU和设备控制器之间又增设了通道。其主要目的是为了建立独立的I/O操作,不仅使数据的传送能独立于CPU,而且也希望有关对I/O操作的组织、管理及其结束处理尽量独立,以保证CPU有更多的时间去进行数据处理。
在设置了通道后,CPU只需向通道发送一条I/O指令。通道在收到该指令后,便从内存中取出本次要执行的通道程序,然后执行该通道程序,仅当通道完成了规定的I/O任务后,才向CPU发中断信号。
实际上,I/O通道是一种特殊的处理机,它具有执行I/O指令的能力,并通过执行通道程序来控制I/O操作。
但I/O通道又与一般的处理机不同,主要表现在以下两个方面:
1)其指令类型单一,这是由于通道硬件比较简单,其所能执行的命令主要局限于与I/O操作有关的指令。
2)通道没有自己的内存,通道所执行的通道程序是放在主机的内存中的,换言之,是通道与CPU共享内存。
根据信息交换方式的不同,可把通道分成以下三种类型:
1)字节多路通道(Byte Multiplexor Channel)它通常都含有许多非分配型子通道,其数量可从几十到数百个,每一个子通道连接一台I/O设备,并控制该设备的I/O操作。这些子通道按时间片轮转方式共享主通道。
2)数组选择通道(Block Selector Channel)只含有一个分配型子通道,在一段时间内只能执行一道通道程序,控制一台设备进行数据传送,致使当某台设备占用了该通道后,便一直由它独占,直至该设备传送完毕释放该通道。
3)数组多路通道(Block Multiplexor Channel)含有多个非分配型子通道,具有很高的数据传输速率,又能
获得令人满意的通道利用率。
中断在操作系统中有特殊重要的地位,它是多道程序实现的基础,进程之间的切换时通过中断来实现的,实现CPU与I/O设备的并行执行也需要中断的支持。中断处理程序是I/O系统中的最低一层,是整个I/O系统的基础。
中断简介
中断:中断实际上是对信号做出的一种反应,即CPU对I/O设备发来的中断信号的一种反应。是由外部设备引起的。俗称外中断。
陷入:陷入是特殊的中断,因为陷入是由CPU内部事件引起的中断,俗称内中断。如地址越界。中断与陷入的区别主要是信号的来源,即CPU内部还是外部。
中断的过程:先中断硬件,然后中断处理程序,首先保存被中断进程的CPU环境,然后转向相应设备的中断处理程序进行处理,处理完成,恢复被中断进程的CPU环境,返回断点继续运行。
中断向量表:每种设备映射一个中断处理程序,把程序的入口地址放在中断向量表的表项中去,为每一个设备的中断请求设规定一个中断信号。多个中断信号,但是根据中断信号的要紧程度的不同来划分出中断的优先级。
中断处理程序
中断处理程序位于I/O系统的底层,直接与硬件进行交互, 在响应一个特定中断的时候,内核会执行一个函数,该函数叫中断处理程序(interrupt handler)或中断服务例程(interrupt service routine,ISR)。产生中断的每个设备都有一个相应的中断处理程序。一个设备的中断处理程序是它设备驱动程序的一部分。中断处理程序与其他内核的真正区别在于:中断处理程序是被内核调用来响应中断的,而它们运行于我们称之为中断上下文的特殊上下文中。
中断处理程序的处理过程:
- 测定是否有未响应的中断信号
- 保护被中断的进程CPU环境
- 转入相应的设备处理程序
- 中断处理
- 恢复CPU现场并退出中断
概述
设备驱动程序通常又称为设备处理程序,它是I/O进程与设备控制器之间的通信程序,又由于它常以进程的形式存在,可简称之为设备驱动进程。其主要任务是接收上层软件发来的抽象I/O要求,如read或write命令,在把它转换为具体要求后,发送给设备控制器,启动设备去执行;此外,它也将从设备控制器发来的信号传送给上层软件。由于驱动程序与硬件密切相关,故应为每一类设备配置一种驱动程序,有时也可为非常类似的两类设备配置一个驱动程序。例如,打印机
设备驱动程序的功能:
- 接收由设备独立性软件发来的命令和参数,并将命令中的抽象要求转换为具体要求。
- 检查用户I/O请求的合法性,了解I/O设备的状态,传递有关参数,设置设备的工作方式。
- 发出I/O命令。
- 及时响应由控制器或通道发来的中断请求,并根据其中断类型调用相应的中断处理程序进行处理。
- 对于设置有通道的计算机系统,驱动程序还应能够根据用户的I/O请求,自动地构成通道程序。
设备驱动程序的特点:
- 驱动程序主要是指在请求I/O的进程与设备控制器之间的一个通信和转换程序。
- 驱动程序与设备控制器和I/O设备的硬件特性紧密相关,因而对不同类型的设备应配置不同的驱动程序。
- 驱动程序与I/O设备所采用的I/O控制方式紧密相关。
- 由于驱动程序与硬件紧密相关,因而其中的一部分必须用汇编语言编写。
- 驱动程序应允许可重入。
- 驱动程序不允许系统调用。
设备处理方式:
根据在设备处理时是否设置进程,以及设置什么样的进程而把设备处理方式分成以下三类:
- 为每一类设备设置一个进程,专门用于执行这类设备的I/O操作。
- 在整个系统中设置一个I/O进程,专门用于执行系统中所有各类设备的I/O操作。
- 不设置专门的设备处理进程,而只为各类设备设置相应的设备处理程序(模块),供用户进程或系统进程调用。
设备驱动程序的处理过程
设备驱动程序的主要任务是启动指定的设备,完成上层指定的I/O工作。在启动前需要完成必要的准备工作:
将抽象要求转换为具体要求
对服务请求镜像校检
检查设备的状态
传送必要的参数
启动I/O的设备
对I/O的控制方式
程序直接控制方式
数据的传送单位是字,采用轮询的方式,CPU的干预很频繁。优点是实现简单,确定是CPU利用率低。
中断驱动方式
引入中断机构,CPU发出指令后可以将等待I/O的进程堵塞,切换到别的进程。I/O完成后控制器会发送信号到CPU,CPU根据信号类型执行相应的中断处理程序,最后恢复等待的进程。由于需要保存和恢复进程的环境,所以需要一些开销。CPU的干预只需要在I/O开始前和完成后,故干预较小,提高了CPU利用率。
DMA方式
又称直接存储器存储。主要用于块设备的控制,相比与终端驱动方式,数据的传送单位是块,数据的流向直接到内存而不经过CPU。仅在传送数据块的开始和结束时才需要CPU干预。
通道控制方式
CPU向通道发送I/O指令,指明操作哪个设备和取什么数据,然后切换到其他进程。通道完成任务后向CPU发送中断信号,让CPU来处理。通道是一个低配的处理机,只能识别一些很单一的指令。相比与DMA方式,数据的传输单位是组。优点:资源利用率高,缺点:实现复杂。
现代I/O系统都增加了与设备无关的I/O软件,以实现设备的独立性,提高OS的可适应性和可扩展性。设备独立性也称设备无关性。为了实现设备独立性,必须在设备驱动程序上设置一层软件,称为设备无关的I/O软件,或设备独立软件。
与设备无关软件的基本概念
基本概念
设备独立性(设备无关性)的含义:应用程序中所用的设备,不局限于使用某个具体的物理设备。
与设备无关的I/O软件(设备独立性软件)含义:在设备驱动程序之上设置一层软件,以实现设备独立性。
以物理设备名使用设备
早期OS中,应用程序在使用I/O设备时,都使用设备的物理名字,但这样会导致很多的问题,比如:不灵活,给用户带来不便。对提高I/O设备的利用率也很不利。
引入逻辑设备名
为了实现与设备的无关性而引入了逻辑设备和物理设备两个概念。逻辑设备是抽象的设备名,如/dev/printer,并不指定哪一台打印机。好处:系统设备分配灵活。可实现I/O重定向。即:用于IO操作的设备可更换,而不必改变应用程序。
逻辑设备名到物理设备名的转换
为了实现逻辑设备名到物理设备名的映射,系统必须设置一张逻辑设备表LUT(Logical Unit Table),能够将应用程序中所使用的逻辑设备名映射为物理设备名,并提供该设备驱动程序的入口地址。
与设备无关的软件
与设备无关的软件是I/O系统的最高层软件,在它下面是设备的驱动程序。总的来说,与设备无关的软件中,包括了执行所有设备的公有操作的软件,具体包括如下几项:
- 设备驱动的统一接口:可以很方便的添加设备的驱动程序。
- 缓冲管理
- 差错控制:包括两类错误,暂时性错误,永久性错误。
- 对独立设备的分配与回收:对独占设备有系统进行统一的分配和回收处理。
- 独立于设备的逻辑数据块:隐藏不同设备的物理数据块大小的差异,向高层软件提供大小统一的逻辑数据块。
设备分配
系统为实现对独占设备的分配,必须在系统中配置相应的数据结构。
1.设备分配中的数据结构
在用于设备分配的数据结构中,记录了对设备或控制器进行控制所需的信息。在进行设备分配时需要如下的数据结构。
- 设备控制表 (DCT):系统为每一个设备都配置了一张设备控制表,用于记录设备的情况。
- 控制器控制表 (COCT):系统为每一个控制器都设置了用于记录控制器情况的控制器控制表。
- 通道控制表 (CHCT):每个通道都有一张通道控制表。
- 系统设备表 (SDT):这是系统范围的数据结构,记录了系统中全部设备的情况,每个设备占一个表目,其中包括有设备类型、设备标识符、设备控制表及设备驱动程序的入口等项。
逻辑设备名到物理设备名映射的实现
为实现与设备的无关性,当应用程序请求使用I/O设备时,应当用逻辑设备名。但系统只识别物理设备名,因此在系统中需要配置一张逻辑设备表,用于将逻辑设备名映射为物理设备名。
大部分的I/O软件都在操作系统内部,但仍然有一小部分在用户层,其中包括与用户程序链接在一起的库函数,以及完全运行于内核之外的假脱机系统等。
系统调用与库函数
- 系统调用
一方面,为使诸进程能有条不紊地使用I/O设备,且能保护设备的安全性,不允许运行在用户态的应用进程去直接调用运行在核心态(系统态)的OS过程。但另一方面,应用进程在运行时,又必须取得OS所提供的服务,否则,应用程序几乎无法运行。为了解决此矛盾,OS在用户层中引入了一个中介过程——系统调用,应用程序可以通过它间接调用OS中的I/O过程,对I/O设备进行操作。
- 库函数
在C语言以及UNIX系统中,系统调用(如read)与各系统调用所使用的库函数(如read)之间几乎是一一对应的。而微软定义了一套过程,称为Win32 API的应用程序接口,程序员利用它们取得OS服务,该接口与实际的系统调用并不一一对应。用户程序通过调用对应的库函数使用系统调用,这些库函数与调用程序连接在一起,被嵌入在运行时装入内存的二进制程序中。
假脱机系统
什么是SPOOLing
技术(假脱机技术) (Simultaneaus Periphernal Operationg OnLing
)
- 定义:在联机的情况下实现的同时外围操作
- 特点:是对脱机输入输出系统的模拟。因此, 必须建立在具有多道程序功能的操作系统上,而且需要高速外存的支持。
- 方式:将数据从输入设备传送到磁盘或反之。
- 通过它可以将一台独占的物理设备虚拟为多台逻辑设备,从而允许多个用户(进程)共享。
SPOOLing
系统的组成
- 输入井和输出井:在磁盘上开辟的两个大存储空间
- 输入缓冲区和输出缓冲区:在内存中开辟的两个缓冲区
- 输入进程
Spi
和输出进程Spo
:是内存中的两个进程- 井管理程序:控制作业与磁盘井之间信息的交换
SPOOLing
系统接收到用户进程的打印输出请求后:由输出进程在输出井中为之申请一个空闲磁盘块区,并将要打印的数据送入其中;输出进程再为用户进程申请一张空白的用户请求打印表,并将用户的打印要求填入其中,再将该表挂到请求打印队列上。当打印机空闲时,输出进程将从请求打印队列的队首取出一张请求打印表,再从输出井把数据送到内存缓冲区,启动打印机打印输出。打印完后,输出进程检查请求打印队列……
SPOOLing
系统的特点
- 提高了I/O的速度,缓和了CPU与低速I/O设备速度不匹配的矛盾
- 利用高速共享设备,将独占设备改造为共享设备
- 实现了虚拟设备功能:用户都感到独占了一台设备
deamon
)守护进程取代假脱机管理进程。执行以下功能:
- 为用户申请磁盘缓冲区的空闲盘块、写入打印数据、返回该盘块的首址。
- 守护进程是允许使用打印机的唯一进程。打印进程要将要求打印的文件放在假脱机文件队列中。并唤醒守护进程。
- 守护进程的任务是按照队列中每个文件的说明执行逐个打印任务,直至全部完成,然后休眠。
- 总之,凡是需要将独占设备改造为共享设备时,都要为该设备配置守护进程和假脱机文件队列
缓冲的引入
缓和CPU与I/O设备间速度不匹配的矛盾
减少CPU中断的频率,放宽对CPU中断响应时间的限制
解决数据粒度不匹配的问题
提高CPU和I/O设备之间的并行性
单缓冲区和双缓冲区
单缓冲(Single Buffer):在设备和处理器之间设置一个缓冲区。设备和处理器交换数据时,先把被交换数据写入缓冲区,然后把需要数据的设备或处理器从缓冲区取走数据。
双缓冲(Double Buffer):双缓冲区机制又称缓冲对换。IO设备输入数据时先输入到缓冲区1,直到缓冲区1满后才输入到缓冲区2,此时操作系统可以从缓冲区1中取出数据放入用户进程,并由CPU计算。双缓冲的使用提高了处理器和输入设备的并行操作的程度。
环形缓冲区:含多个大小相等的缓冲区,每个缓冲区中有一个缓冲区,最后一个缓冲区指针指向第一个缓冲区,多个缓冲区构成一个环形。用于输入输出时,还需要有两个指针in和out。对输入而言,首先要从设备接收数据到缓冲区中,in指针指向可以输入数据的第一个空缓冲区;当运行进程需要数据时,从循环缓冲去中去一个装满数据的缓冲区,并从此缓冲区中提取数据,out指针指向可以提取数据的第一个满缓冲区。输出正好相反。
缓冲池 (Buffer Pool):由多个系统共用的缓冲区组成,缓冲区按其使用状况可以形成三个队列:空缓冲队列、装满输入数据的缓冲队列(输入队列)和装满输出数据的缓冲队列(输出队列)。还应具有四种缓冲区:用于收容输入数据的工作缓冲区、用于提取输入数据的工作缓冲区、用于收容输出数据的工作缓冲区、用于提取输出数据的工作缓冲区。
磁盘性能简述
早起的磁盘调度算法
磁盘调度的目标:对所有请求访问磁盘的进程进行合理调度,使平均寻道时间最少,使对磁盘的平均访问时间最小。
FCFS 先来先服务
多个进程的磁盘I/O请求构成一个随机分布的请求队列,磁盘I/O执行顺序按磁盘请求的先后顺序。
SSTF(ShortestSeekTimeFirst
)最短寻道时间优先
选择从当前位置出发移动最少的磁盘I/O请求,使每次磁头移动时间最少。不一定是最短平均柱面定位时间
可能会有进程处于饥饿状态。 改进:考虑距离的同时,更优先考虑方向。引进SCAN算法。
基于扫描的磁盘调度算法
SCAN 磁盘电梯调度算法
规定磁头移动方向:自里向外,再自外向里移动。后续请求,哪个在规定方向上距离最近,就先执行哪个。存在“错过”问题:反方向较近的55号磁道请求的进程相对“饥饿”很久。改进:将SCAN规定的移动方向改为“单向移动”。引进CSCAN算法。
CSCAN
由里向外后,再由里向外。前述算法存在“磁臂粘着”——磁头静止在一个磁道上,导致其它进程无法及时进行磁盘I/O。(因:高密度盘,进程的读写可能集中在某一磁道)。改进→N-Step-SCAN算法。
N-Step-SCAN
将磁盘请求队列分成长为N 的子队列 ,按FCFS选择子队列,队列内又按SCAN算法。N=1时,就是FCFS,N很大时就是SCAN。
F-SCAN
N-Step-SCAN的简化。请求队列只分为两个子队列,当前一个队列,按SCAN算法执行,扫描期间新生成的组成一个队列,等待被扫描。
操作系统中的文件管理系统专门管理外存上的文件,并把对文件的存取、共享和保护等手段提供给用户。在系统运行时,计算机以进程为基本单位进行资源的调度和分配;而在用户进行的输入、输出中,则以文件为基本单位。
文件管理系统的管理功能是将其管理的程序和数据通过组织为一系列文件的方式来实现的。
数据项、记录和文件
数据项
:在文件系统中数据项是最低级的数据组织形式。可把数据项分成基本数据项和组合数据项。基本数据项:用于描述对象的某种属性的字符集,是数据组织中可以以命名的最小逻辑数据单位,包括名字和类型。又称字段;组合数据项:由于某个基本数据项组成。
记录
:记录是一组数据项的集合,用于描述一个对象在某方面的属性。根据对象所处的环境不同可以把它作为不同的对象。
文件
:文件是指由创建者所定义的一组相关信息的集合,可分为有结构文件和无结构文件两种。有结构文件由一组相似记录组成,如报考某学校的所有考生的报考信息记录;而无结构文件则被看成是一个字符流,比如一个二进制文件或字符文件。文件有一定的属性,如名称、类型、位置、大小等。
文件名和类型
扩展名 | 文件类型 | 含义 |
---|---|---|
.exe .com. bin | 可执行文件 | 可以运行的机器语言程序 |
.obj .o | 目标文件 | 编译后尚未连接的语言程序 |
.c .cc .java .pas | 源文件 | 各种语言的源代码 |
.bat .sh | 批文件 | 又命令解析程序处理的命令 |
.lib .a .so .dll | 库文件 | 供程序员使用的例程序 |
按照性质和用途可以分为:
1)系统文件:又系统软件构成的文件,通常只允许执行或读取。
2) 用户文件:又用户的源代码,目标文件、可执行文件等构成的文件。
3) 库文件:又标准子例程及常用的例程等所构成的文件。
按照数据形式可分为:源文件,目标文件,可执行文件。
按照存取控制属性:可执行文件,只读文件,读写文件。
按照组织形式和处理分式:普通文件,目录文件,特殊文件
文件系统的层次结构
文件系统的模型可以分为下图三个结构:
1)对象及其属性:位于层次结构中的最底层,文件管理系统的对象指:文件,目录,磁盘存储空间。
2)对对象操纵和管理的软件集合:位于中层,管理系统的核心部分,实现大多数文件夹管理的功能,如管理存储空间,目录,读写管理,保护和共享。与文件系统有关的软件包括四个层次:I/O控制层,基本文件系统层,基本I/O管理程序,逻辑文件系统。
3)文件系统的接口:命令接口,程序接口。
文件操作
基本文件操作
创建文件:分配空间->在文件目录中创建一个目录项->在目录项中记录文件名、外存地址等信息。
删除文件:在文件目录中删除目录项->回收占用的存储空间
读文件:根据用户给出的文件名去查找目录,得出被读文件在外存中的位置。
写文件:根据文件名查找目录,找到指定文件的目录项,利用目录中的写指针进行写操作。
其他文件操作:
打开,关闭,修改属性,操作目录,设置共享。。。
文件逻辑结构类型
系统的所有文件从不同角度看存在两种形式的结构:逻辑结构,物理结构。逻辑结构是从用户观点出发观察到的文件组织形式。采用合适的逻辑结构有助于提高文件的检索速度,方便修改文件和减低文件在外存上的存储代价。物理结构又称文件的存储结构。
按照文件是否有机构分类:有结构文件包括定长记录,变长记录。无结构文件包又称流式文件,如可执行文件。
按照文件的组织方式分类:顺序文件(按照某种顺序排序记录),索引文件(建立索引表为每个记录设置一个表项对记录的检索加速),索引顺序文件(建立索引表,为一组记录中的第一个记录设置一个索引表项)。顺序文件的排列方式一般可分为串结构(非顺序结构,检索麻烦),顺序结构(按照关键字排序)。顺序文件的优缺点:对文件的记录进行批量存取是效率高,但修改记录比较困难。
记录寻址
记录寻址包括隐式寻址和显式寻址,用于查找顺序文件中一条记录。
索引文件
索引顺序文件
索引顺序表是顺序和索引两种组织形式的结合。索引顺序文件将顺序文件中所有记录分为若干个组,为顺序文件建立一张索引表,在索引表中为每组中的第一个记录建立一个索引项,其中含有该记录的关键字值和指向该记录的指针。根据索引表的级数可以分为一级索引顺序文件,二级索引顺序文件等。
直接文件和哈希文件
直接文件:不必检索,根据给定的关键字直接获得指定记录的物理地址。
哈希文件:目前应用最为广泛的一种直接文件。利用哈希函数将关键字转换成为相应记录的地址。
与文件管理系统和文件集合相关联的是文件目录,它包含有文件的信息,包括属性、位置和所有权等,这些信息都由操作系统进行管理。
文件控制块和索引节点
同进程管理一样,为实现目录管理,操作系统中引入了文件控制块的数据结构。
文件控制块(FCB)是用来存放控制文件需要的各种信息的数据结构,以实现“按名存取”。FCB的有序集合称为文件目录,一个FCB就是一个文件目录项。为了创建一个新文件,系统将分配一个FCB并存放在文件目录中,称为目录项。FCB主要包含以下信息:基本信息(如文件名、文件的物理位置、文件的逻辑结构、文件的物理结构等),存取控制信息(如文件的存取权限),使用信息三类信息(如文件建立时间、修改时间等)。
在检索目录文件的过程中,只用到了文件名,仅当找到一个目录项时,才需要从该目录项中独处该文件的物理地址。也就是说,在检索目录时,文件的其他描述信息不会用到,也不许调入内存,因此,有的系统(如UNIX)采用了文件名和文件描述信息分开的方法,文件描述信息单独形成一个称为索引节点的数据结构,简称为i节点。在文件目录中的每个目录项仅由文件名和指向该文件所对应的i节点的指针构成。
简单的文件目录
单级目录结构:
在整个文件系统中只建立一张目录表,每个文件占一个目录项,目录项中包括文件名,扩展名,长度,文件类型等信息。当建立一个新文件时,必须先检索所有目录项以确保没有“重名”的现象,然后在该目录中增设一项,把FCB的全部信息保存在该项中。当删除一个文件时,先从该目录中找到该文件的目录项,回收该文件所占用的存储空间,然后再清除该目录项。单级目录结构实现了按名存取,但是存在查找速度慢、文件不允许重名、不便于文件共享等缺点,而且对于多用户的操作系统显然是不适用的。
二级目录结构:
将文件目录分成主文件目录MFD和用户文件目录UFD两级。主文件目录项纪录用户名及相应用户文件所在的存储位置。用户文件目录项记录该用户文件的FCB信息。当某用户与对其文件进行访问时,只需要搜索该用户对应的UFD,这即解决了不同用户文件的重名问题,也在一定程度上保证了文件的安全。两级目录结构可以解决多用户之间的文件重名问题,文件系统可以在目录上实现访问限制,但是两级结构对于用户结构内部结构没有任何帮助。用户如果需要在某个任务上进行合作和访问那其他文件时便会产生很多问题。
树形结构的文件目录
将两级目录结构的层析加以推广,就形成了多级目录结构,及树形目录结构。用户要访问某个文件时用文件的路径名标识文件,文件路径名是一个字符串,由从根目录出发到所找文件的通路商的所有目录名与数据文件名用分隔符/连接起来而成。从根目录出发的路径称为绝对路径。当层次较多时,每次从根目录查询浪费时间,于是加入了当前目录,进程对各文件的访问都是相对于当前目录进行的。当用户要访问某个文件时,使用相对路径标识文件,相对路径由从当前目录出发到所找文件通路商所有目录名与数据文件名用分隔符/链接而成。通常,每个用户都有自己的当前目录,登陆后自动进入该用户的当前目录。操作系统提供一条专门的系统调用,供用户随时改变当前目录。树形目录结构可以很方便的对文件进行分类,层次结构清晰,也能够更有效地进行文件的管理和保护。但是,在属性目录中查找一个文件,需要按路径名主机访问中间节点,这就增加了磁盘访问次数,无疑将影响查询速度。
文件共享十多个用户进程共享同一份文件,系统中只需保留该文件的一份副本。如果系统不能提供共享功能,那么每个需要该文件的用户都要有各自的副本,会造成对存储空间的极大浪费。
现代常用的两种文件共享方法有:在树形结构的目录中,当有两个或多个用户要共享一个子目录或文件时,必须将共享文件或子目录连接到两个或多个用户的目录中,才能方便的找到该文件。
外存的组织方式
文件存储空间的管理
为了知道磁盘上哪些盘块是可用于分配的,系统为磁盘设置一个磁盘分配表,用于记住可供分配的存储空间情况。
提高磁盘I/O速度的途径
提高磁盘可靠性的技术
第一级容错技术SFT-I
用于防止因磁盘表面缺陷导致数据丢失。包括双份目录、分配表、写后读校检措施。
第二级容错技术SFT-II
防止磁盘驱动器和控制器故障导致系统不能正常工作。包括:磁盘镜像,磁盘双工
基于集群技术的容错功能
后备系统
数据一致性控制
进程描述与控制:进程概念、线程概念、同步、通信
调度与死锁: 目标、算法、实时调度、死锁、
存储器:程序的装入和链接、静态动态链接重定位概念、分配算法、
虚拟存储器:概念、页面置换算法
输入输出:设备无关性、
操作系统的五大功能是:进程管理 、作业管理、内存管理、文件管理、作业管理。
计算机操作系统是方便用户、管理和控制计算机硬软件的系统软件。
程序和进程的区别:程序只是一组指令的有序集合,它本身没有任何运行的含义,它只是 一个静态的实体。而进程则不同,它是程序在某个数据集上的执行。 进程是一个动态的实体,它有自己的生命周期。它因创建而产生,因调度而运行,因等待资源或事件而被处于等待状态,因完成任务而被撤消。进程还具有并发性和交往性,这也与程序的封闭性不同。
进程与线程的区别:一个程序至少有一个进程,一个进程至少有一个线程。进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。
通道及其作用:通道是一个独立于CPU的专管输入/输出控制的处理机,它控制设备与内存直接进行数据交换。引入通道的目的是:使数据的传输独立于CPU,使CPU从繁重的I/O工作中解脱出来. 它有自己的通道指令,这些通道指令受CPU启动,并在操作结束时向CPU发中断信号。
作业调度与进程调度的区别:作业调度是处理机调度中的高级调度,作业指用户程序及其所需的数据和命令的集合,作业调度程序的主要功能是审查系统是否能满足用户作业的资源要求以及按照一定的算法来选取作业; 进程调度是低级调度,其主要功能是根据一定的算法将CPU分派给就绪队列中的一个进程,进程调度是操作系统中最基本的一种调度,其调度策略的优劣直接影响整个系统的性能。