操作系统实习报告
目录
1.4.2程序结构 3
1.4.2数据结构 3
2.4.1程序结构 8
2.4.2数据结构 8
4.2数据结构 13
设计程序模拟单处理机系统中的进程调度算法,在短作业优先调度算法、 时间片轮转调度、最高优先级优先算法三种算法中选择两种实现。
每个进程由一个进程控制块(PCB)表示。进程控制块可以包含如下信息: 进程名、优先数、到达时间、需要运行时间、已用CPU时间、进程状态等。进程的优先数及需要的运行时间可以事先人为地指定(也可以由随机数 产 生)。进程的到达时间为进程输入的时间。
进程的运行时间以时间片为单位进行计算。
每个进程的状态可以是就绪W(Wait)、运行R(Run)或完成F(Finish)3 中状态之一。
该算法先比较作业运行时间长短,运行时间短的作业先执行,如果运行 时间相同,则按照到到达时间执行,到达时间早的先执行。
1.4.1程序结构
①输入部分:
void input(PCB *p,int N)
{
int i;
printf("请输入进程的名称、到达时间和运行时间:\nfor example:a 0 100\n");
for(i=0;i<=N-1;i++)
{
printf("请输入第%d个进程的信息:\n",i+1); scanf("%s%f%f",&p[i].name,&p[i].arrivetime,&p[i].runtime);
}
}
②输出部分:
oid output(PCB *p,int N)
{
int k;
printf("优先运行顺序:");
printf("%s",p[0].name); for(k=1;k<N;k++)
{
printf("-->%s",p[k].name); }
printf("\n各个进程的信息:\n");
printf("\n名称\t到达\t运行\t开始\t完成\t周转\t带权周转 \n");
for(k=0;k<N;k++)
{
printf("%s\t%-.2f\t%-.2f\t%-.2f\t%-.2f\t%-.2f\t%-.2f\t\n",p[k]. name,p[k].arrivetime,p[k].runtime,p[k].starttime,p[k].finishtim e,p[k].zztime,p[k].dqzztime);
}
}
③排序部分:用冒泡排序法将到达时间降序排序
void sort(PCB *p,int N)
{
for(int i=0;i<N;i++)
for(int j=0;j<i;j++)
if(p[i].arrivetime<p[j].arrivetime) {
PCB t;
t=p[i];
p[i]=p[j];
p[j]=t;
}
}
④计算部分:为了得到每个进程的结束时间
void deal(PCB *p,int N)/{
int k;
for(k=0;k<N;k++)
{
if(k==0) {
p[k].starttime=p[k].arrivetime;
p[k].finishtime=p[k].starttime+p[k].runtime;
}
else
{
p[k].starttime=p[k-1].finishtime;
p[k].finishtime=p[k].starttime+p[k].runtime;
}
}
for(k=0;k<N;k++)
{
p[k].zztime=p[k].finishtime-p[k].arrivetime;
p[k].dqzztime=p[k].zztime/p[k].runtime;
}
}
1.4.2数据结构
struct PCB
{
char name[10];
float arrivetime;
float runtime;
float starttime;
float finishtime;
float zztime;
float dqzztime;
};
PCB a[100];
void sjff(PCB *p,int N)
{
float arrivetime=0,runtime=0,starttime=0,finishtime=0,zztime=0,dqzztime=0;
sort(p,N);
for(int m=0;m<N-1;m++)
{
if(m==0)
p[m].finishtime=p[m].arrivetime+p[m].runtime; else
{
if(p[m-1].finishtime >=p[m].arrivetime )
{
p[m].starttime=p[m-1].finishtime;}/
else
{
p[m].starttime =p[m].arrivetime;}
p[m].finishtime=p[m].starttime+p[m].runtime;
}
int i=0;
for(int n=m+1;n<=N-1;n++)
{
if(p[n].arrivetime<=p[m].finishtime)
i++;
}
float min=p[m+1].runtime;
int next=m+1;//m+1=n
for(int k=m+1;k<m+i;k++)
{
if(p[k+1].runtime<min)
{
min=p[k+1].runtime;
next=k+1;
}
}
PCB temp;
temp=p[m+1];
p[m+1]=p[next];
p[next]=temp;
}
deal(p,N);
output(p,N);
}
1.6程序流程图
设计程序模拟单处理机系统中的进程调度算法,在短作业优先调度算法、时间片轮转调度、最高优先级优先算法三种算法中选择两种实现。
每个进程由一个进程控制块(PCB)表示。进程控制块可以包含如下信息:进程名、优先数、到达时间、需要运行时间、已用CPU时间、进程状态等。
进程的优先数及需要的运行时间可以事先人为地指定(也可以由随机数产生)。进程的到达时间为进程输入的时间。
进程的运行时间以时间片为单位进行计算。
每个进程的状态可以是就绪W(Wait)、运行R(Run)或完成F(Finish)3中状态之一。
该算法按照先来先服务执行进程,用time()函数计算进程运行时间,先将 进程初始化信息进行备份,用while条件判断进程是否全部执行完毕,如果进 程执行完毕则跳出循环结束计算。
2.4.1程序结构
①输入函数:
int pinput() /*进程参数输入*/
{
int i;
printf("请输入进程个数:\n");
scanf("%d",&counter);
printf("请输入时间片长度:\n");
scanf("%d",&timecounter);
for(i=0; i<counter; i++)
{
printf("**************************************\n");
printf("请输入进程名称、到达时间、运行时间:(中间用 空格隔开)\n");
scanf("%s%f%f",tasks[i].name,&tasks[i].arrivetime,& tasks[i].runtime);
tasks[i].starttime=0;
tasks[i].finishtime=0;
tasks[i].runflag=0; //运行是否结束
tasks[i].startflag=0;//是否首次被执行
}
return 0;
}
②输出函数:
int poutput()
{
int i;
float dqzztime=0,zztime=0,w=0;
printf("进程名 到达时间 运行时间 开始时间 结束 时间 周转时间 带权周转时间\n");
for(i=0; i<counter; i++)
{
zztime=tasks[i].finishtime-tasks[i].arrivetime;
dqzztime=zztime/tasks[i].runtime;
printf("%s\t%5.3f\t%5.3f\t%5.3f\t %5.3f\t%5.3f\t%5.3 f\n",tasks[i].name,tasks[i].arrivetime,tasks[i].run time,tasks[i].starttime,tasks[i].finishtime,zztime, dqzztime);
}
return 0;
}
③判断函数:判断进程是否全部执行完毕
int charge()
{
int k;
int superflag=0;
for(k=0; k<counter; k++)
{
if(tasks[k].runflag==0)
{
superflag=1;
return superflag;
break;
}
else
{
superflag=0;
}
}
return superflag;
}
2.4.2数据结构
struct task_struct
{
char name[10]; /*进程名称*/
float arrivetime; /*到达时间*/
float starttime; /*开始运行时间*/
float runtime; /*运行时间*/
float finishtime; /*运行结束时间*/
int runflag; /*调度标志*/
int startflag; //是否为第一次开始调度
} tasks[MAX];
int counter; /*实际进程个数*/
int pinput();
int timecounter=0;
int poutput(); /*调度结果输出*/
int time();
int charge();//判断是否所有的进程都被执行过
int time()
{
float temp=0;
int i;
int j=0;
int k=0;
struct task_struct copy_task[MAX];//备份
for(i=0; i<counter; i++)
{
copy_task[j++]=tasks[i];//对进程的初始化信息备份
}
temp=tasks[0].arrivetime;//temp=第一个进程的到达时间
while(charge())
{
for(i=0; i<counter; i++)
{
if(tasks[i].arrivetime>temp)
{
temp=tasks[i].arrivetime;
}
if(tasks[i].runflag==0)//第i个进程还未结束
{
if(tasks[i].startflag==0)
{
tasks[i].starttime=temp;
tasks[i].startflag=1;
}
if(tasks[i].runtime/timecounter>1)
{
tasks[i].runtime=tasks[i].runtime-timecounter;
temp=temp+timecounter;
}
else if(tasks[i].runtime-timecounter==0)
{
temp=temp+timecounter; tasks[i].finishtime=temp;
tasks[i].runflag=1;//标记该进程已经执行完毕
tasks[i].runtime=copy_task[i].runtime;
}
else//仅剩下不足一倍的时间片,则剩余运行时间除以时间片长度<1
{
temp=temp+tasks[i].runtime;
tasks[i].finishtime=temp;
tasks[i].runflag=1;//标记该进程已经运行完毕
tasks[i].runtime=copy_task[i].runtime;
}
}
}
}
return 0;
}
设定开始磁道号寻道范围,依据起始扫描磁道号和最大磁道号数,随机产生要进行寻道的磁道号序列。选择磁盘调度算法,显示该算法的磁道访问顺序,计算出移动的磁道总数和平均寻道总数。
1. 最短寻道优先算法SSTF:该算法选择这样的进程:其要求访问的
磁道与当前磁头所在的磁道距离最近,以使每次的寻道时间最短。
2.扫描算法SCAN:该算法不仅考虑到欲访问的磁道与当前磁道间的距离,更优先考虑的是磁头当前的移动方向。例如,当磁头正在自里向外移动时,SCAN算法所考虑的下一个访问对象,应是其欲访问的磁道既在当前磁道之外,又是距离最近的。这样自里向外地访问,直至再无更外的磁道需要访问时,才将磁臂换向为自外向里移动。
3.循环扫描算法CSCAN:CSCAN算法规定磁头单向移动,例如,只是自里向外移动,当磁头移到最外的磁道并访问后,磁头立即返回到最里的欲访问的磁道,亦即将最小磁道号紧接着最大磁道号构成循环,进行循环扫描。
该算法用vvector标准模板库模拟有许多扇区的磁盘,用srand()和rand()函数随机生成磁盘序列,存放到outfile文件流里面,设计一个选择函数,用switch选择需要调用的SSTF、SCAN、CSCAN算法,也用switch选择是否结束进程。
①随机生成序列函数,用srand和rand随机生成序列
void request(vector<int>&m_vec,ofstream &outfile){
cout<<"随机生成磁盘序列:"<<endl;
int n = 0;
srand(time(NULL));
n = rand() % 20 + 1; //rand()是一个产生随机数的函数,与srand一起 用,rand()%20+1:n的取值为1-20
int temp = 0;
for(int i=0;i<n;i++){
temp = rand() % 100; //temp的取值为0-100
m_vec.push_back(temp); // 将随机生成的temp数输入到vector里面
cout<<temp<<" ";
outfile<<temp<<endl; //outfile输出数据文件流,输出到输出文件中
}
cout<<endl;
position = rand() % 100; //当前磁道为随机生成的0-100之间的数
cout<<"当前磁道:"<<position<<endl;
}
②最短寻道算法:
void SSTF(vector<int>m_vec,int position){
dis = 0;
average_distance = 0;
sort(m_vec.begin(),m_vec.end()); //从小到大排序
int i = 0;
for(vector<int>::iterator it=m_vec.begin();it!=m_vec.end();it++){
if(position >= *it) //找到position所在磁道
i++;
}
int count = 0;
int left = i-1; //i为下标
int right = i;
while(count<m_vec.size()){ //选择扫描方向,如果
if((left >=0 && abs(m_vec[right]-position) > abs(m_vec[left]-position)) || right>=m_vec.size()){
dis += abs(m_vec[left]-position);
Sleep(500);
cout<<"->"<<m_vec[left];
position = m_vec[left];
left--;
}
else{ //选择从右边开始扫描
dis += abs(m_vec[right]-position);
Sleep(500);
cout<<"->"<<m_vec[right];
position = m_vec[right];
right++;
}
count++;
}
compute_dis(m_vec,dis,average_distance);
}
③扫描算法:
void SCAN(vector<int>m_vec,int position){
dis = 0;
average_distance = 0;
sort(m_vec.begin(),m_vec.end()); //从小到大排序
int i = 0;
for(vector<int>::iterator it=m_vec.begin();it!=m_vec.end();it++){
if(position >= *it)
i++; //找到position所在的磁道
}
int left = i - 1; //先从外到内扫描
int right = i;
while(left >= 0){
dis += abs(position - m_vec[left]);
Sleep(500);
cout<<"->"<<m_vec[left];
position = m_vec[left];
left --;//当左边的序列走完之后跳出这个while循环
}
while(right < m_vec.size()){
dis += abs(position - m_vec[right]);
Sleep(500);
cout<<"->"<<m_vec[right];
position = m_vec[right];
right ++;
}
compute_dis(m_vec,dis,average_distance);
}
④循环扫描算法:
void CSCAN(vector<int>m_vec,int position){ //循环扫描算法
dis = 0;
average_distance = 0;
sort(m_vec.begin(),m_vec.end()); //从小到大排序
int i = 0;
for(vector<int>::iterator it=m_vec.begin();it!=m_vec.end();it++){
if(position >= *it)
i++; //找到position所在的磁道
}
int left = i - 1; //先从外到内扫描
int right = i;
while(left >= 0){
dis += abs(position - m_vec[left]);
Sleep(500);
cout<<"->"<<m_vec[left];
position = m_vec[left];
left --;
}
int len = m_vec.size()-1;
while(len >= right){ //从最外侧在是扫描一遍,像梳头发一样
dis += abs(position - m_vec[len]);
Sleep(500);
cout<<"->"<<m_vec[len];
position = m_vec[len];
len --;
}
compute_dis(m_vec,dis,average_distance);
}
⑤计算平均距离算法:
void compute_dis(vector<int>m_vec,int &dis,double &average_distance){
average_distance = (double)dis / (double)m_vec.size();
}
int choose_algorithm(vector<int>m_vec){
cout<<endl<<endl;
cout<<"本实验可用的调度算法有以下3种:"<<endl;
cout<<"1.SSTF 2.SCAN 3.CSCAN 4.结束本序列的调度 5.结束程序"<<endl;
int choice = 0;
cout<<"选择:"<<endl;
cin>>choice;
cout<<endl;
while(choice!=4 && choice!=5){
cout<<"磁盘请求的服务状况:"<<endl;
cout<<position;
switch(choice){
case 1:
SSTF(m_vec,position);break;
case 2:
SCAN(m_vec,position);break;
case 3:
CSCAN(m_vec,position);break;
default:
cout<<"******非法输入!******"<<endl<<endl;break;
}
if(choice<=5 && choice>=1)
print();
cout<<"选择:"<<endl;
cin>>choice;
}
if(choice == 5)
return 0;
else
cout<<endl<<endl; //清空输出缓冲区,相当于将vertor初始化
return 1;
}
6.程序流程图
每一次课程设计度让我学到了在平时课堂不可能学到的东西。不一定我的课程设计能够完成得有多么完美,但是我总是很投入的去研究去学习。但是每完成一个任务我都兴奋不已。总体而言我的课设算是达到了老师的基本要求。总结一下有以下体会。
1、网络真的很强大,用在学习上将是一个非常高效的助手。几乎所有的资料都能够在网上找到。也因为这样,整个课程设计下来,我浏览的相关网页已经超过了100个(不完全统计)。当然网上的东西很乱很杂,自己要能够学会筛选。
2、同学间的讨论,这是很重要的。老师毕竟比较忙。对于课程设计最大的讨论伴侣应该是同学了。能和学长学姐讨论当然再好不过了,没有这个机会的话,和自己班上同学讨论也是能够受益匪浅的。大家都在研究同样的问题,讨论起来,更能够把思路理清楚,相互帮助,可以大大提高效率。
3、敢于攻坚,越是难的问题,越是要有挑战的心理。这样就能够达到废寝忘食的境界。当然这也是不提倡熬夜的,毕竟有了精力才能够打持久战。但是做课设一定要有状态,能够在吃饭,睡觉,上厕所都想着要解决的问题,这样你不成功都难。