操作系统处理器调度董迎顺.docx
《操作系统处理器调度董迎顺.docx》由会员分享,可在线阅读,更多相关《操作系统处理器调度董迎顺.docx(15页珍藏版)》请在冰豆网上搜索。
操作系统处理器调度董迎顺
实验三处理器调度
【实验目的】
在采用多道程序设计的系统中,往往有若干个进程同时处于就绪状态。
当就绪进程个数大于处理器数时,就必须依照某种策略来决定哪些进程优先占用处理器。
本实验模拟在单处理器情况下的处理器调度,帮助学生加深了解处理器调度的工作。
【实验内容】
选择一个调度算法,实现处理器调度。
【实验指导】
本实验有两个题,学生可选择其中的一题做实验。
第一题:
设计一个按优先数调度算法实现处理器调度的程序。
[提示]:
(1)假定系统有五个进程,每一个进程用一个进程控制块PCB来代表,进程控制块的格式为:
进程名
指针
要求运行时间
优先数
状态
其中,进程名——作为进程的标识,假设五个进程的进程名分别为P1,P2,P3,P4,P5。
指针——按优先数的大小把五个进程连成队列,用指针指出下一个进程的进程控制块的首地址,最后一个进程中的指针为“0”。
要求运行时间——假设进程需要运行的单位时间数。
优先数——赋予进程的优先数,调度时总是选取优先数大的进程先执行。
状态——可假设有两种状态,“就绪”状态和“结束”状态。
五个进程的初始状态都为“就绪”,用“R”表示,当一个进程运行结束后,它的状态为“结束”,用“E”表示。
(2)在每次运行你所设计的处理器调度程序之前,为每个进程任意确定它的“优先数”和“要求运行时间”。
(3)为了调度方便,把五个进程按给定的优先数从大到小连成队列。
用一单元指出队首进程,用指针指出队列的连接情况。
例:
队首标志
K2
K1
P1
K2
P2
K3
P3
K4
P4
K5
P5
0
K4
K5
K3
K1
2
3
1
2
4
1
5
3
4
2
R
R
R
R
R
PCB1
PCB2
PCB3
PCB4
PCB5
(4)处理器调度总是选队首进程运行。
采用动态改变优先数的办法,进程每运行一次优先数就减“1”。
由于本实验是模拟处理器调度,所以,对被选中的进程并不实际的启动运行,而是执行:
优先数-1
要求运行时间-1
来模拟进程的一次运行。
提醒注意的是:
在实际的系统中,当一个进程被选中运行时,必须恢复进程的现场,让它占有处理器运行,直到出现等待事件或运行结束。
在这里省去了这些工作。
(5)进程运行一次后,若要求运行时间0,则再将它加入队列(按优先数大小插入,且置队首标志);若要求运行时间=0,则把它的状态修改成“结束”(E),且退出队列。
(6)若“就绪”状态的进程队列不为空,则重复上面(4)和(5)的步骤,直到所有进程都成为“结束”状态。
(7)在所设计的程序中应有显示或打印语句,能显示或打印每次被选中进程的进程名以及运行一次后进程队列的变化。
(8)为五个进程任意确定一组“优先数”和“要求运行时间”,启动所设计的处理器调度程序,显示或打印逐次被选中进程的进程名以及进程控制块的动态变化过程。
第二题:
设计一个按时间片轮转法实现处理器调度的程序。
[提示]:
(1)假定系统有五个进程,每一个进程用一个进程控制块PCB来代表。
进程控制块的格式为:
进程名
指针
要求运行时间
已运行时间
状态
其中,进程名——作为进程的标识,假设五个进程的进程名分别为Q1,Q2,Q3,Q4,Q5。
指针——进程按顺序排成循环队列,用指针指出下一个进程的进程控制块的首地址,最后一个进程的指针指出第一个进程的进程控制块首地址。
要求运行时间——假设进程需要运行的单位时间数。
已运行时间——假设进程已经运行的单位时间数,初始值为“0”。
状态——有两种状态,“就绪”和“结束”,初始状态都为“就绪”,用“R”表示。
当一个进程运行结束后,它的状态为“结束”,用“E”表示。
(2)每次运行所设计的处理器调度程序前,为每个进程任意确定它的“要求运行时间”。
(3)把五个进程按顺序排成循环队列,用指针指出队列连接情况。
另用一标志单元记录轮到运行的进程。
例如,当前轮到P2执行,则有:
标志单元
K2
K1
Q1
K2
Q2
K3
Q3
K4
Q4
K5
Q5
K2
K3
K4
K5
K1
2
3
1
2
4
1
0
0
0
0
R
R
R
R
R
PCB1
PCB2
PCB3
PCB4
PCB5
(4)处理器调度总是选择标志单元指示的进程运行。
由于本实验是模拟处理器调度的功能,所以,对被选中的进程并不实际的启动运行,而是执行:
已运行时间+1
来模拟进程的一次运行,表示进程已经运行过一个单位的时间。
请同学注意:
在实际的系统中,当一个进程被选中运行时,必须置上该进程可以运行的时间片值,以及恢复进程的现场,让它占有处理器运行,直到出现等待事件或运行满一个时间片。
在这时省去了这些工作,仅用“已运行时间+1”来表示进程已经运行满一个时间片。
(5)进程运行一次后,应把该进程的进程控制块中的指针值送到标志单元,以指示下一个轮到运行的进程。
同时,应判断该进程的要求运行时间与已运行时间,若该进程的要求运行时间已运行时间,则表示它尚未执行结束,应待到下一轮时再运行。
若该进程的要求运行时间=已运行时间,则表示它已经执行结束,应指导它的状态修改成“结束”(E)且退出队列。
此时,应把该进程的进程控制块中的指针值送到前面一个进程的指针位置。
(6)若“就绪”状态的进程队列不为空,则重复上面的(4)和(5)的步骤,直到所有的进程都成为“结束”状态。
(7)在所设计的程序中应有显示或打印语句,能显示或打印每次选中进程的进程名以及运行一次后进程队列的变化。
(8)为五个进程任意确定一组“要求运行时间”,启动所设计的处理器调度程序,显示或打印逐次被选中的进程名以及进程控制块的动态变化过程。
长春大学计算机科学技术学院实验报告
日期_______________地点______________指导教师_____________成绩
实验三处理器调度
一、写出程序代码并分析运行结果
#include
#include
#include
typedefstructDATA
{
charpname[10];//进程名
floattime;//要求运行时间数
intove;//优先级
charflag;//状态
}DATA;
typedefstructpcb
{
DATAdata;
structpcb*next;
}pcb;
intflag=5;//假设有五个进程
pcb*init(pcb*p)//初始化
{
p=(pcb*)malloc(sizeof(DATA));
p->next=NULL;
returnp;
}
voidshow(pcb*p)//输出显示
{
if(!
flag)
{
printf("\n没有正在运行的进程,或进程已经全部执行完毕。
\n");
}
else
{printf("\n名称");
printf("");
printf("执行时间");
printf("");
printf("优先数");
printf("");
printf("状态\n");
while(p->next)
{p=p->next;
printf("%s",p->data.pname);
printf("");
printf("%1.0f",p->data.time);
printf("");
printf("%d",p->data.ove);
printf("");
printf("%c\n\n",p->data.flag);
}
}
}
voiddel(pcb*h)//进程执行完成后的删除
{
pcb*p;
p=h;
p=p->next;
if(p->data.flag=='E')
{
printf("有一个进程执行完成:
\n");
printf("进程的名称为:
%s\n",p->data.pname);
p=p->next;
h->next=p;
flag--;
}
}
voidin(pcb*h)//从键盘中输入数据
{
inti=0;
pcb*pc,*l;
pc=h;
printf("请依次输入五个进程的名称、执行时间、优先数:
(输入时进程与进程之间用回车来隔开!
)\n");
for(i;i{
l=init(l);
scanf("%s%f%d",&l->data.pname,&l->data.time,&l->data.ove);
rewind(stdin);
if(!
l->data.time)
{
l->data.flag='E';
}
else
l->data.flag='R';
l->next=NULL;
pc->next=l;
pc=pc->next;
}
}
voidsoar(pcb*p)//对于这五个进程按其优先级进行排序
{
pcb*q;
pcb*h;
inti=0;
intj;
q=init(q);
h=p->next;
for(i;i{
for(j=0;j<(flag-1);j++)
{
if(h->data.time)
{
if(h->data.ovenext->data.ove)
{
q->data=h->data;
h->data=h->next->data;
h->next->data=q->data;
}
h=h->next;
}
else
{
printf("有一个进程执行完成:
\n");
printf("进程的名称为:
%s\n",h->data.pname);
flag--;
}
}
h=p->next;
}
if(flag)
printf("\n目前优先级最高的进程的名称是:
%s\n所以执行此进程!
",p->next->data.pname);
}
voidrun(pcb*h)//执行程序
{
h=h->next;
h->data.time--;
h->data.ove--;
if(!
h->data.time)
{
h->data.flag='E';
}
}
voidmain()
{
pcb*p;
charc;
p=init(p);
in(p);
soar(p);
show(p);
del(p);
while(flag)
{
run(p);
del(p);
soar(p);
show(p);
c=getch();
rewind(stdin);
}
}
程序运行时的初值
a12
b34
c56
d31
e55
运行结果:
ⅰ进程控制块的初始状态。
ⅱ选中运行的进程名以及选中进程运行后的各进程控制块状态。
二、思考题
1、试比较FCFS和SPF两种进程调度算法。
答:
FCFS每次调度从进程队列中选择最先进入该队列的进程,为之分配处理机,运行。
SPF是从队列中选择运行时间最短的作业,优先调入内存运行。
但是SPF必须预知
作业的运行时间,一般会偏长估计,而且对长作业不利,容易出现饥饿现象。
该调
度算法完全未考虑作业的紧迫程度,故不能保证紧迫性作业得到及时处理
2、请详细说明可通过哪些途径预防死锁。
答:
死锁发生的条件:
1、资源不能共享,需要只能由一个进程或者线程使用
2、请求且保持,已经锁定的资源自给保持着不释放
3、不剥夺,自给申请到的资源不能被别人剥夺
4、循环等待
想预防死锁,把上面四个条件破坏一个就可以了。
可以利用银行家算法。
按同一顺序访问对象。
如果所有并发事务按同一顺序访问对象,则发生死锁的可能性会降低。
例如,如果两个并发事务获得 Supplier 表上的锁,然后获得 Part 表上的锁,则在其中一个事务完成之前,另一个事务被阻塞在 Supplier 表上。
第一个事务提交或回滚后,第二个事务继续进行。
不发生死锁。
将存储过程用于所有的数据修改可以标准化访问对象的顺序
避免事务中的用户交互。
避免编写包含用户交互的事务,因为运行没有用户交互的批处理的速度要远远快于用户手动响应查询的速度,例如答复应用程序请求参数的提示。
例如,如果事务正在等待用户输入,而用户去吃午餐了或者甚至回家过周末了,则用户将此事务挂起使之不能完成。
这样将降低系统的吞吐量,因为事务持有的任何锁只有在事务提交或回滚时才会释放。
即使不出现死锁的情况,访问同一资源的其它事务也会被阻塞,等待该事务完成。
保持事务简短并在一个批处理中。
在同一数据库中并发执行多个需要长时间运行的事务时通常发生死锁。
事务运行时间越长,其持有排它锁或更新锁的时间也就越长,从而堵塞了其它活动并可能导致死锁。
保持事务在一个批处理中,可以最小化事务的网络通信往返量,减少完成事务可能的延迟并释放锁
使用低隔离级别。
确定事务是否能在更低的隔离级别上运行。
执行提交读允许事务读取另一个事务已读取(未修改)的数据,而不必等待第一个事务完成。
使用较低的隔离级别(例如提交读)而不使用较高的隔离级别(例如可串行读)可以缩短持有共享锁的时间,从而降低了锁定争夺
使用绑定连接。
使用绑定连接使同一应用程序所打开的两个或多个连接可以相互合作。
次级连接所获得的任何锁可以象由主连接获得的锁那样持有,反之亦然,因此不会相互阻塞