目录
1. 操作系统概论
2. 进程同步
3. 进程调度与死锁
4. 内存管理及虚拟存储器
5. 设备虚拟化技术
6. 文件存储空间管理
1. (简答题) 有两个程序,程序A依次使用CPU计10s,使用设备甲计5s,使用CPU计5s,使用设备乙计10s,使用CPU计10s;程序B依次使用设备甲计10s,使用CPU计 10s,使用设备乙计5s,使用CPU计5s,使用设备乙计10s.在单道程序环境下先执行程序A再执行程序B,计算CPU的利用率是多少?在多道程序环境下,CPU 利用率是多少?
单道程序环境下:
CPU共使用:10S+5S+10S+10S+5S=40S
总时间:(10+5+5+10+10+10+10+5+5+10)S=80S
利用率:(40/80)100%=50%
多道程序环境下:
0~10,程序A使用CPU10S,同时程序B在使用设备甲
10~20,A在使用设备甲5S,同时B使用CPU10S(A等待了5S)
20~25,A使用CPU5S,B在使用设备乙5S
25~30,B使用CPU5S,A进行使用设备乙5S(A还没有用完)
30~35,A还在使用设备乙5S,这个时候B只能等着(CPU空闲中!)
35~45,A使用CPU10S,B使用设备乙10S以上CPU有效时间是40S,
共运行时间是45S利用率:(40/45)100%=88.9%
2. (简答题)设某计算机系统有一个CPU、一台输入设备、一台打印机。现有两个进程同时进入就绪状态,且进程A先得到CPU运行,进程B后运行,进程A的运行轨迹为:计算50ms,打印信息100ms,再计算50ms,打印信息 100ms,结束,进程B的运行轨迹为:计算50ms,输入数据80ms,再计算100ms,结束。
试画出它们的时序关系图(可以用甘特图),并说明:
1)开始运行后,CPU有无空闲等待?若有,在哪段时间内等待?计算CPU的利用率.
2)进程A运行时有无等待现象?若有,在什么时候发生等待现象?
3)进程B运行时有无等待现象?若有,在什么时候发生等待现象?
1)开始运行后,CPU有无空闲等待?若有,在哪段时间内等待?计算CPU的利用率.
运行次序为:
0~50ms A计算,
50~100ms B计算,A打印
100~150ms,A打印,B输入
150~200ms,A计算,其中150~180ms B继续输入
200~300ms A打印,B计算
运行开始后,在100~150ms时,CPU空闲等待。
CPU利用率为:250/300=83.3%。
2)进程A运行时有无等待现象?若有,在什么时候发生等待现象?
答:进程A没有空闲
3)进程B运行时有无等待现象?若有,在什么时候发生等待现象?
答:进程B有空闲,在开始后0ms到50ms之间等待,180ms到200ms之间等待
1. (简答题)某车站售票厅,最多可容纳20名购票者进入,当售票厅中少于20名购票者时,其厅外的购票者可立即进入,否则,需在外等待。若把一个购票者看作是一个进程,请回答下列问题:
①写出用P/V操作管理这些并发进程时,信号量的初值以及信号量的各种取值的含义;
②根据所定义的信号量,编写相应的进程同步算法,以保证进程能够正确地并发执行。
# include
# include
# include
# include
# include
# include
# include
# include
//定义一信号量s,初始值为20。表示空闲位置的数量
// S=0表示售票厅中已有20名顾客(购票者) ;
sem_t s;
void* Ticket(void* param) {
long ticketid = (long)param;
while (1){
sem_wait(&s);
printf("Customer %ld: is buying\n", ticketid);
sleep(3);
sem_post(&s);
}
pthread_exit(0);
}
int main() {
sem_init(&s,0,20);
pthread_t tid[30];
for (int i = 0; i < 30 ; ++i) {
pthread_create(&tid[i], NULL , Ticket , (void*)i);
}
int c=0;
while (1){
c = getchar();
if (c=='q' || c=='Q'){
for (int i = 0; i < 30; ++i) {
pthread_cancel(tid[i]);
}
break;
}
}
return 0;
}
2. (简答题)设数据采集系统中有一个单缓冲区,数据采集与数据处理共享该缓冲区,试用整型信号量编写一个该系统中数据采集进程与数据处理进程的同步算法。
# include
# include
# include
# include
# include
# include
# include
# include
//empty 同步信号量,表示剩余空间的数量
// full 同步信号量,表示产品的数量
//单个缓冲区可以不设置互斥信号量
sem_t full,empty;
//生产者
void *get(void* param) {
long threadid = (long)param;
while (1){
sem_wait(&empty);
printf("ThreadId %ld : collect data\n", threadid);
sleep(6);
sem_post(&full);
}
pthread_exit(0);
}
//消费者
void *compute(void* param) {
long threadid = (long)param;
while (1){
sem_wait(&full);
printf("ThreadId %ld : compute data \n",threadid);
sleep(3);
sem_post(&empty);
}
pthread_exit(0);
}
int main() {
//线程id
pthread_t tid[4];
//第二个参数 不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享
//第三个参数 给出了信号量的初始值。
sem_init(&empty, 0, 1);
sem_init(&full, 0, 0);
//两个生产者,两个消费者
pthread_create(&tid[0], NULL , compute, (void*)0);
pthread_create(&tid[1], NULL , get, (void*)1);
pthread_create(&tid[2], NULL , compute, (void*)2);
pthread_create(&tid[3], NULL, get, (void*)3);
int c=0;
while (1){
c = getchar();
if (c=='q' || c=='Q'){
for (int i = 0; i < 4; ++i) {
pthread_cancel(tid[i]);
}
break;
}
}
return 0;
}
3. (简答题)请分析Linux源代码中task_struct各个字段含义,进程链表是如何组织的。
struct task_struct {
volatile long state; //说明了该进程是否可以执行,还是可中断等信息
unsigned long flags; //Flage 是进程号,在调用fork()时给出
int sigpending; //进程上是否有待处理的信号
mm_segment_t addr_limit; //进程地址空间,区分内核进程与普通进程在内存存放的位置不同
//0-0xBFFFFFFF for user-thead
//0-0xFFFFFFFF for kernel-thread
//调度标志,表示该进程是否需要重新调度,若非0,则当从内核态返回到用户态,会发生调度
volatile long need_resched;
int lock_depth; //锁深度
long nice; //进程的基本时间片
//进程的调度策略,有三种,实时进程:SCHED_FIFO,SCHED_RR, 分时进程:SCHED_OTHER
unsigned long policy;
struct mm_struct *mm; //进程内存管理信息
int processor;
//若进程不在任何CPU上运行, cpus_runnable 的值是0,否则是1 这个值在运行队列被锁时更新
unsigned long cpus_runnable, cpus_allowed;
struct list_head run_list; //指向运行队列的指针
unsigned long sleep_time; //进程的睡眠时间
//用于将系统中所有的进程连成一个双向循环链表, 其根是init_task
struct task_struct *next_task, *prev_task;
struct mm_struct *active_mm;
struct list_head local_pages; //指向本地页面
unsigned int allocation_order, nr_local_pages;
struct linux_binfmt *binfmt; //进程所运行的可执行文件的格式
int exit_code, exit_signal;
int pdeath_signal; //父进程终止时向子进程发送的信号
unsigned long personality;
//Linux可以运行由其他UNIX操作系统生成的符合iBCS2标准的程序
int did_exec:1;
pid_t pid; //进程标识符,用来代表一个进程
pid_t pgrp; //进程组标识,表示进程所属的进程组
pid_t tty_old_pgrp; //进程控制终端所在的组标识
pid_t session; //进程的会话标识
pid_t tgid;
int leader; //表示进程是否为会话主管
struct task_struct *p_opptr,*p_pptr,*p_cptr,*p_ysptr,*p_osptr;
struct list_head thread_group; //线程链表
struct task_struct *pidhash_next; //用于将进程链入HASH表
struct task_struct **pidhash_pprev;
wait_queue_head_t wait_chldexit; //供wait4()使用
struct completion *vfork_done; //供vfork() 使用
unsigned long rt_priority; //实时优先级,用它计算实时进程调度时的weight值
//it_real_value,it_real_incr用于REAL定时器,单位为jiffies, 系统根据it_real_value
//设置定时器的第一个终止时间. 在定时器到期时,向进程发送SIGALRM信号,同时根据
//it_real_incr重置终止时间,it_prof_value,it_prof_incr用于Profile定时器,单位为jiffies。
//当进程运行时,不管在何种状态下,每个tick都使it_prof_value值减一,当减到0时,向进程发送
//信号SIGPROF,并根据it_prof_incr重置时间.
//it_virt_value,it_virt_value用于Virtual定时器,单位为jiffies。当进程运行时,不管在何种
//状态下,每个tick都使it_virt_value值减一当减到0时,向进程发送信号SIGVTALRM,根据
//it_virt_incr重置初值。
unsigned long it_real_value, it_prof_value, it_virt_value;
unsigned long it_real_incr, it_prof_incr, it_virt_value;
struct timer_list real_timer; //指向实时定时器的指针
struct tms times; //记录进程消耗的时间
unsigned long start_time; //进程创建的时间
//记录进程在每个CPU上所消耗的用户态时间和核心态时间
long per_cpu_utime[NR_CPUS], per_cpu_stime[NR_CPUS];
//内存缺页和交换信息:
//min_flt, maj_flt累计进程的次缺页数(Copy on Write页和匿名页)和主缺页数(从映射文件或交换
//设备读入的页面数); nswap记录进程累计换出的页面数,即写到交换设备上的页面数。
//cmin_flt, cmaj_flt, cnswap记录本进程为祖先的所有子孙进程的累计次缺页数,主缺页数和换出页面数。
//在父进程回收终止的子进程时,父进程会将子进程的这些信息累计到自己结构的这些域中
unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap;
int swappable:1; //表示进程的虚拟地址空间是否允许换出
//进程认证信息
//uid,gid为运行该进程的用户的用户标识符和组标识符,通常是进程创建者的uid,gid
//euid,egid为有效uid,gid
//fsuid,fsgid为文件系统uid,gid,这两个ID号通常与有效uid,gid相等,在检查对于文件
//系统的访问权限时使用他们。
//suid,sgid为备份uid,gid
uid_t uid,euid,suid,fsuid;
gid_t gid,egid,sgid,fsgid;
int ngroups; //记录进程在多少个用户组中
gid_t groups[NGROUPS]; //记录进程所在的组
//进程的权能,分别是有效位集合,继承位集合,允许位集合
kernel_cap_t cap_effective, cap_inheritable, cap_permitted;
int keep_capabilities:1;
struct user_struct *user;
struct rlimit rlim[RLIM_NLIMITS]; //与进程相关的资源限制信息
unsigned short used_math; //是否使用FPU
char comm[16]; //进程正在运行的可执行文件名
//文件系统信息
int link_count, total_link_count;
//NULL if no tty 进程所在的控制终端,如果不需要控制终端,则该指针为空
struct tty_struct *tty;
unsigned int locks;
//进程间通信信息
struct sem_undo *semundo; //进程在信号灯上的所有undo操作
struct sem_queue *semsleeping; //当进程因为信号灯操作而挂起时,他在该队列中记录等待的操作
//进程的CPU状态,切换时,要保存到停止进程的task_struct中
struct thread_struct thread;
//文件系统信息
struct fs_struct *fs;
//打开文件信息
struct files_struct *files;
//信号处理函数
spinlock_t sigmask_lock;
struct signal_struct *sig; //信号处理函数
sigset_t blocked; //进程当前要阻塞的信号,每个信号对应一位
struct sigpending pending; //进程上是否有待处理的信号
unsigned long sas_ss_sp;
size_t sas_ss_size;
int (*notifier)(void *priv);
void *notifier_data;
sigset_t *notifier_mask;
u32 parent_exec_id;
u32 self_exec_id;
spinlock_t alloc_lock;
void *journal_info;
};
① 组织方式:进程PCB中,会有一个变量 state 来表示进程的当前状态。如:1表示创建态、2表示就绪态、3表示运行态…为了对同一个状态下的各个进程进行统一的管理,操作系统会将各个进程的PCB组织起来。主要的进程组织方式有链接方式以及索引方式两种。
② 链接方式:这是把具有同一状态的 PCB,用其中的链接字链接成一个队列。这样,可以形成绪队列、若干个阻塞队列和空白队列等。对其中的就绪队列常按进程优先级的高低排列,把优先级高的进程的 PCB 排在队列前面。此外,也可根据阻塞原因的不同而把处于阻塞状态的进程的 PCB 排成等待 I/O 操作完成的队列和等待分配内存的队列等。
③ 索引方式: 系统根据所有进程的状态建立几张索引表。例如,就绪索引表、阻塞索引表等,并把各索引表在内存的首地址记录在内存的一些专用单元中。在每个索引表的表目中,记录具有相应状态的某个 PCB 在 PCB 表中的地址。
1. (简答题) 简述多级反馈队列调度算法的基本原理,分析它对短作业、长作业的调度性能。
1)多级反馈队列调度算法的实现思想:
应设置多个就绪队列,并为各个队列赋予不同的优先级,第1级队列的优先级最高,第2级队列次之,其余队列的优先级逐次降低。
赋予各个队列中进程执行时间片的大小也各不相同,在优先级越高的队列中,每个进程的运行时间片就越小。例如,第2级队列的时间片要比第1级队列的时间片长一倍,以此类推。
当一个新进程进入内存后,首先将它放入第1级队列的末尾,按FCFS原则排队等待调度。当轮到该进程执行时,如它能在该时间片内完成,便可准备撤离系统,否则,调度程序便将该进程转入第2级队列的末尾,再同样地按FCFS 原则等待调度执行。如此下去,当一个长进程从第1级队列依次降到第 n 级队列后,在第 n 级队列中便釆用时间片轮转的方式运行。
仅当第1级队列为空时,调度程序才调度第2级队列中的进程运行;仅当第1 ~ (i-1)级队列均为空时,才会调度第i级队列中的进程运行。如果处理机正在执行第i级队列中的某进程时,又有新进程进入优先级较高的队列(第 1 ~ i-1中的任何一个队列),则此时新进程将抢占正在运行进程的处理机,即由调度程序把正在运行的进程放回到第i级队列的末尾,把处理机分配给新到的更高优先级的进程。
2)多级反馈队列的优势有:
终端型作业用户:短作业优先。
短批处理作业用户:周转时间较短。
长批处理作业用户:经过前面几个队列得到部分执行,不会长期得不到处理。
2. (简答题)在银行家算法中,若出现下述资源分配情况,试问:
(1)状态安全,可用资源可以满足p0进程的需求,把分配给进程p0的资源进行回收。最后序列为 p0->p3->p1->p2->p4。
(2)不能分配给它。分配完之后,可用资源只剩下(0,4,0,0),不能满足任何一个进程的资源需求,进程会进入死锁状态。所以不能分配出去。
1. (简答题) 简述分页系统中如何实现地址变换,分析页表大小对系统性能的影响;有快表时如何实现地址变换,影响快表变换效率的因素有哪些?
在分页系统中,允许将进程的每一页离散地存储在内存的任一物理块中,为能保证进程的正常运行,系统建立了页表。在进程地址空间内的所有页,依次在页表中有一页表项,其中记录了相应页在内存中的对应物理块号,进程执行时通过查找页表,即可找到每页在内存中的位置,即页表的作业是实现页号到物理块号的地址映射。当地址空间变得非常大时,页表也将变得非常大,将占用相当大的内存空间。对于一个具有32位地址空间的分页系统,规定页面大小为4 KB,则在每个进程页表中的页表项可达到1 MB,又因为每个页表项占用4 B,故仅每个进程的页表项就要占用4 MB的内存空间,而且要求是连续的,这显然是不现实的。可以从以下两个方面来解决这个问题。(1) 对页表所需的空间采用离散分配。(2) 只将当前所需的一部分页表项调入内存,其余表项仍驻留在外存中,仅当必须时才调入内存。具体的实现方案是采用两级页表。在用户逻辑地址原来的划分基础上,将页表部分再分为页表索引项和页表两部分,也就是说对页表也进行分页。对于投入运行的程序,将其页表索引调入内存,而对其页表仅调入少量的项。程序运行时如找不到相应的页表,则产生一个中断,请求操作系统将该页表调入内存。两级页表适应了大地址空间的需要,实现了虚拟存储系统,但增加了地址变换的开销和操作系统管理上的复杂性。
2. (简答题) 在一个请求分页系统中,分别采用FIFO、OPT、LRU、LFU、简单Clock 页面置换算法时,假如一个作业的页面走向为4 , 3 , 2 ,1 , 4 , 3 , 5 , 4 ,3 , 2 , 1 ,5,当分配给该作业的物理块数M分别为3和4时,试计算访问过程中所发生的缺页次数和缺页率 ? 比较所得结果。
页面置换算法详细介绍https://blog.csdn.net/gl620321/article/details/106144576当物理块数M=3时
FIFO:共发生 9次缺页中断 缺页率=9/12=75%
LRU:共发生 10次缺页中断 缺页率=10/12=83.3%
OPT:共发生 7次缺页中断 缺页率=7/12=58.3%
当物理块数M=4时
FIFO:共发生 10次缺页中断 缺页率=10/12=83.3%
LRU:共发生 8次缺页中断 缺页率=8/12=66.7%
OPT:共发生 6次缺页中断 缺页率=6/12=50%
上述结果可以看出,对先进先出算法而言,增加分配给作业的内存块数反而出现缺页次数增加的异常现象。
1. (简答题) 请解释何为设备虚拟化,实现设备虚拟化的关键技术有哪些?
请解释何为设备虚拟化?
(1)设备虚拟是通过虚拟技术将一台独占设备虚拟成多台逻辑设备,供多个用户进程同时使用, 通常把这种经过虚拟的设备称为虚拟设备。虚拟存储的发展借鉴了计算机领域里很多成功的设计思想,从虚存、磁盘技术、RAID到IBM的大型机等的设计思想中都汲取了许多成功的经验。
(2)设备虚拟是指把独占设备经过某种技术处理改造成虚拟设备。可虚拟设备是指一台物理设备在采用虚拟技术后,可变成多台逻辑上的虚拟设备,则可虚拟设备是可共享的设备,将它同时分配给多个进程使用,并对这些访问该物理设备的先后次序进行控制。
实现设备虚拟化的关键技术有哪些?
(1)请求分页系统(请求分页的页表机构、缺页中断机构、地址变换机构)
(2)请求分段系统(请求分段的段表机构、缺段中断机构、地址变换机构)
2. (简答题) 试说明SPOOLing 系统的组成。在实现后台打印时,SPOOLing 系统应为请求I/O的进程提供哪些服务?
① 由输出进程在输出井中申请一空闲盘块区,并将要打印的数据送入其中:
② 输出进程为用户进程申请空白用户打印表,填入打印要求,将该表挂到请求打印队列。
③ 一旦打印机空闲输出进程便从请求打印队列的队首取出一张请求打印表,根据表中要求将要打印的数据从输出井传送到内存缓冲区,再由打印机进行打印。
1. (简答题) 在MS-DOS中有两个文件A 和B,A占用11、12、16和14四个盘块;B 占用13、18和20三个盘块。试画出在文件A和B中各盘块间的链接情况及FAT的情况。
2. (简答题) 在UNIX中,如果一个盘块的大小为1KB,每个盘块号占4个字节,即每块可放256个地址。请转换下列文件的字节偏移量为物理地址:(1)9999; (2)18000;(3)420000。当访问的地址为400000时,需要读多少次盘块?
答:首先将逻辑文件的字节偏移量转换为逻辑块号和块内偏移量,就是将【字节偏移量】/八盘块大小)],商为逻辑块号,余数是块内偏移量。在FCB中第0-9个地址为直接地址,第10个为一次间接地址第11个地址为二次间接地址,第12个地址为三次间接地址。再将文件的逻辑块号转换为物理块号。使用多重索引结构,在索引节点中根据逻辑块号通过直接索引或间接索引找到对应的物理块号。
(1)9999/1024=9余783,则逻辑块号为9,直接索引第9个地址得到物理块号,块内偏移地址为783.
(2)18000/1024=17余592,则逻辑块号为10<17<10+256,通过一次间接索引在第10个地址可得到物理块号,块内偏移地址为592.
(3)420000/1024=410余160,则逻辑块号为10+256<410,通过二次间接索引在第11个地址可得到一次间址再由此得到二次间址再找到物理块号,其块内偏移地址160。
(4)400000/256=1562余5,则需要读1563次盘块。
3. (简答题) 某操作系统磁盘文件空间共500块,若用字长为32位的位示图管理磁盘空间,试问:(1)位示图需要多少字?
(2)第i字第j位对应的块号是多少?
(3)给出申请/归还一块的工作流程。
① 位示图需要的字数计算:NT(500/32=15.625)=16个字。
② 块号b=(i-1)*32+j
③ 申请的过程:顺序扫描位示图、找到空闲块并分配、修改位示图mp[j]=1。
归还的过程:找到回收盘块在位示图中的行和列,修改位示图mp[i,j]=0。