操作系统A

李美蓉

目录

  • 1 操作系统引论
    • 1.1 计算机操作方式的演变
    • 1.2 什么是操作系统
    • 1.3 操作系统的结构
    • 1.4 操作系统的特性
  • 2 进程管理
    • 2.1 进程描述
    • 2.2 进程状态及转换
    • 2.3 进程控制
    • 2.4 进程的并发执行
    • 2.5 进程同步与互斥
    • 2.6 信号量机制及应用
    • 2.7 生产者消费者问题
    • 2.8 读者写者问题
    • 2.9 哲学家就餐问题
    • 2.10 进程通信
    • 2.11 消息缓冲区队列机制
  • 3 线程
    • 3.1 什么是线程
    • 3.2 线程实现
  • 4 处理机调度
    • 4.1 处理机调度概述
    • 4.2 作业调度
    • 4.3 进程调度
    • 4.4 实时调度
  • 5 死锁
    • 5.1 死锁概念及资源分配图
    • 5.2 死锁的必要条件及预防
    • 5.3 死锁避免
    • 5.4 死锁检测和解除
  • 6 存储器管理
    • 6.1 存取器概述及连续分配方式(一)
    • 6.2 动态分区分配及可重定位分区分配
    • 6.3 分页存储管理
    • 6.4 页表结构
    • 6.5 分段及段页式存储管理方式
  • 7 虚拟存储器管理
    • 7.1 虚拟存储技术
    • 7.2 请求分页存储管理
    • 7.3 页面置换算法
    • 7.4 抖动与工作集
    • 7.5 请求分段存储管理
  • 8 磁盘存储器系统
    • 8.1 磁盘存储器的结构
    • 8.2 磁盘调度
    • 8.3 廉价磁盘冗余阵列(RAID)
    • 8.4 提高磁盘I/O的其他方法
    • 8.5 磁盘可靠性技术
  • 9 输入输出系统
    • 9.1 I/O硬件系统
    • 9.2 I/O控制方式
    • 9.3 中断处理程序及设备驱动程序
    • 9.4 设备无关性软件
    • 9.5 缓冲管理
    • 9.6 用户层软件及Spooling
  • 10 文件系统
    • 10.1 文件及逻辑结构
    • 10.2 文件目录结构
    • 10.3 连续分配及链接分配
    • 10.4 索引分配
    • 10.5 空闲空间管理
  • 11 操作系统实验
    • 11.1 实验一  Linux基本命令
    • 11.2 实验二 进程管理
    • 11.3 实验三 进程间通信
    • 11.4 实验四 处理机调度
    • 11.5 实验五 存储管理
    • 11.6 实验六 文件管理
实验四 处理机调度

4.1 实验目的

多道程序设计中,往往有若干个进程同时处于就绪状态。当就绪进程个数大于处理器数时,就必须依照某种策略来决定哪些进程优先占用处理器。本实验要求学生:

1)理解进程的各个状态、进程控制块PCB的结构。

2)理解处理调度算法,模拟在单处理器情况下的处理器调度

4.2 背景知识

1)熟悉C语言源程序的调试和编译知识。

2)掌握优先数调度算法时间片轮转法的原理。

4.3 实验内容

1)设计一个按优先数调度算法实现处理器调度的程序。

[提示]:① 假定系统有五个进程,每一个进程用一个进程控制块PCB来代表,进程控制块的格式为:

进程名

指针

要求运行时间

优先数

状态

其中,进程名——作为进程的标识,假设五个进程的进程名分别为P1P2P3P4P5

指针——按优先数的大小把五个进程连成队列,用指针指出下一个进程的进程控制块的首地址,最后一个进程中的指针为“0”。

要求运行时间——假设进程需要运行的单位时间数。

优先数——赋予进程的优先数,调度时总是选取优先数大的进程先执行。

状态——可假设有两种状态,“就绪”状态和“结束”状态。五个进程的初始状态都为“就绪”,用“R”表示,当一个进程运行结束后,它的状态为“结束”,用“E”表示。

在每次运行你所设计的处理器调度程序之前,为每个进程任意确定它的“优先数”和“要求运行时间”。

为了调度方便,把五个进程按给定的优先数从大到小连成队列。用一单元指出队首进程,用指针指出队列的连接情况。例:

  队首标志

 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

 处理器调度总是选队首进程运行。采用动态改变优先数的办法,进程每运行一次优先数就减1”。由于本实验是模拟处理器调度,所以,对被选中的进程并不实际的启动运行,只进行相应的参数的修改,即执行:

优先数-1

要求运行时间-1

来模拟进程的一次运行。

提醒注意的是:在实际的系统中,当一个进程被选中运行时,必须恢复进程的现场,让它占有处理器运行,直到出现等待事件或运行结束。在这里省去了这些工作。

 进程运行一次后,若要求运行时间¹0,则再将它加入队列(按优先数大小插入,且置队首标志);若要求运行时间=0,则把它的状态修改成“结束”(E),且退出队列。

 “就绪”状态的进程队列不为空,则重复上面的步骤,直到所有进程都成为“结束”状态。

 在所设计的程序中应有显示或打印语句,能显示或打印每次被选中进程的进程名以及运行一次后进程队列的变化。

 为五个进程任意确定一组“优先数”和“要求运行时间”,启动所设计的处理器调度程序,显示或打印逐次被选中进程的进程名以及进程控制块的动态变化过程。

 2)设计一个按时间片轮转法实现处理器调度的程序。

[提示]:① 假定系统有五个进程,每一个进程用一个进程控制块PCB来代表。进程控制块的格式为:

进程名

指针

要求运行时间

已运行时间

状态

其中,进程名——作为进程的标识,假设五个进程的进程名分别为Q1Q2Q3Q4Q5

指针——进程按顺序排成循环队列,用指针指出下一个进程的进程控制块的首地址,最后一个进程的指针指出第一个进程的进程控制块首地址。

要求运行时间——假设进程需要运行的单位时间数。

已运行时间——假设进程已经运行的单位时间数,初始值为“0”。

状态——有两种状态,“就绪”和“结束”,初始状态都为“就绪”,用“R”表示。当一个进程运行结束后,它的状态为“结束”,用“E”表示。

 每次运行所设计的处理器调度程序前,为每个进程任意确定它的“要求运行时间”。

 把五个进程按顺序排成循环队列,用指针指出队列连接情况。另用一标志单元记录轮到运行的进程。例如,当前轮到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

  处理器调度总是选择标志单元指示的进程运行。由于本实验是模拟处理器调度的功能,所以,对被选中的进程并不实际的启动运行,只进行相应的参数的修改,即执行:

已运行时间+1

来模拟进程的一次运行,表示进程已经运行过一个单位的时间。

请同学注意:在实际的系统中,当一个进程被选中运行时,必须置上该进程可以运行的时间片值,以及恢复进程的现场,让它占有处理器运行,直到出现等待事件或运行满一个时间片。在这时省去了这些工作,仅用“已运行时间+1”来表示进程已经运行满一个时间片。

 进程运行一次后,应把该进程的进程控制块中的指针值送到标志单元,以指示下一个轮到运行的进程。同时,应判断该进程的要求运行时间与已运行时间,若该进程的要求运行时间¹已运行时间,则表示它尚未执行结束,应待到下一轮时再运行。若该进程的要求运行时间=已运行时间,则表示它已经执行结束,应指导它的状态修改成“结束”(E)且退出队列。此时,应把该进程的进程控制块中的指针值送到前面一个进程的指针位置。

 “就绪”状态的进程队列不为空,则重复上面的的步骤,直到所有的进程都成为“结束”状态。

 在所设计的程序中应有显示或打印语句,能显示或打印每次选中进程的进程名以及运行一次后进程队列的变化。

 为五个进程任意确定一组“要求运行时间”,启动所设计的处理器调度程序,显示或打印逐次被选中的进程名以及进程控制块的动态变化过程。

4.4 参考程序

4.4.1 按优先数调度算法实现处理器调度的参考程序

#include<iostream>  

#include<string>

 using namespace std;  

//-----------------------     

 struct _proc  //定义一个结构体表示进程的PCB

 {       

char name[32];   //进程名    

struct _proc *next;  //指向下一个PCB的指针

int run_time;    //   要求运行的时间    

int priority;        //   优先数

int state;//进程状态

};

_proc *root;  

     //向就绪队列中插入进程,按照降序  

void Insert(_proc* pr)  

{      

_proc *q=root;     

_proc *p=root->next;  

if(root->state!=0)      

{               

while(p!=NULL)         

{              

if(p->priority>pr->priority)

{                  

q=p;                  

p=p->next;              

}              

else             

{                  

break;              

}          

}       

}

pr->next=p;//插入进程结点     

q->next=pr;      

++root->state;//进程个数加1

}    

 //创建进程  

_proc Creat(char name[],int priority,int run_time)  

{      

_proc pr;    

strcpy(pr.name,name);    

pr.priority=priority;     

pr.run_time=run_time;     

pr.state=0;      

pr.next=NULL;      

return pr;  

}   

 //删除就绪队列中队首进程  

_proc* Delete()  

{      

_proc *pr=root->next; //此时pr为指向结构体的指针,指向队首进程     

root->next=root->next->next;      

--root->state;  //进程个数减1    

return pr; //返回被删除进程的地址

}    

 //对就绪队列排序,按照降序  

void Sort()  

{      

if(root->next->run_time==0)//队首进程的要执行时间为0时,从就绪队列中删除该进程      

{          

Delete();          

root->next->state=1;      

}      

else//不为0时,先删除,再根据变化后的优先级,插入到相应位置      

{          

_proc *pr=Delete();         

Insert(pr);      

}  

}    

void OutPut()  

{      //取队首的进程,模拟进程执行,输出执行进程名  

cout<<root->next->name<<endl;

--root->next->priority;//动态改变优先数,优先级减1      

--root->next->run_time;//运行时间减1   

}    

void Solve()  

{      //定义根结点,指向第一个进程      

root=new _proc;      

root->state=0;//队列中的进程个数       

root->next=NULL;      

//创建几个进程,并插入就绪队列      

_proc pr1=Creat("p1",2,1);

Insert(&pr1);   

_proc pr2=Creat("p2",3,5);      

Insert(&pr2);        

_proc pr3=Creat("p3",1,3);      

Insert(&pr3);        

_proc pr4=Creat("p4",2,4);      

Insert(&pr4);        

_proc pr5=Creat("p5",4,2);      

Insert(&pr5);           

cout<<"调度序列"<<endl;    //输出  

while(root->state!=0)      

{             

OutPut();  //取队首进程模拟执行一个单位时间数     

Sort();   //重新排序   

}  

}    

int main()

{     

Solve();        

getchar();    

getchar();    

return 0;  

}   

4.4.2 按时间片轮转法实现处理器调度的参考程序。

#include<iostream>  

#include<string>  

using namespace std;  

//-----------------------      

struct _proc  //定义一个结构体表示进程的PCB

{       

char name[32];   //进程名    

struct _proc *next;    //指针    

int run_time;  //要求运行的时间     

int alloc_time;  //已运行的时间   

int state;//进程状态  

};  

_proc *root;

  //向就绪队列中插入进程,按照降序

void Insert(_proc* pr)  

{    

if(root->next==NULL)     

{         

root=pr;         

pr->next=pr;        

return;   

}   

pr->next=root->next;//插入   

root->next=pr;

root=pr;

}   

 //创建进程

_proc Creat(char name[],int run_time,int alloc_time)

{      

_proc pr;    

strcpy(pr.name,name); //进程名取参数名

pr.run_time=run_time; //取参数的要求运行时间

pr.alloc_time=alloc_time; //取参数的已运行时间

pr.state=0;     

pr.next=NULL;   

return pr;

}   

//删除就绪队列中对首进程

void Delete()

{   

if(root->next==root)  

{    //队列已为空   

root=NULL;        

return;  

}    

root->next=root->next->next;

}   

//输出进程号,模拟进程执行

void OutPut()

{     

cout<<root->next->name<<endl;//输出

++root->next->alloc_time;//已运行时间加1

}   

void Solve()  

{      //定义根结点,指向下一个运行的进程  

root=new _proc;  

root->state=0;//队列中的进程个数

root->next=NULL;

//创建几个进程,并插入就绪队列     

_proc pr1=Creat("Q1",2,1);

Insert(&pr1);        

_proc pr2=Creat("Q2",3,0);

Insert(&pr2);       

_proc pr3=Creat("Q3",1,0);

Insert(&pr3);   

_proc pr4=Creat("Q4",2,0);    

Insert(&pr4);       

_proc pr5=Creat("Q5",4,0);

Insert(&pr5);        

cout<<"调度序列:"<<endl;  //输出  

while(root!=NULL)//一直循环遍历  

{             

OutPut();//执行root指向的进程       

if(root->next->alloc_time==root->next->run_time)//执行完毕    

{             

Delete();//从就绪队列中删除该进程           

continue;         

}       

root=root->next;//root指针后移,执行下一个进程做准备   

}

}

int main()

{     

Solve();      

getchar();

return 0;

}