第一篇:第三章 处理机调度与死锁小结
第三章 处理机调度与死锁
重点与难点小结
1.高优先权调度和基于时间片的轮转调度算法
1)
2)
3)时间片轮转调度
4)多级反馈队列调度
2.常用的几种实时调度算法
1)最早截止时间优先(EDF)算法
2)最低松弛度优先(LLF)算法
3.死锁的基本概念
1)2)4.预防死锁的方法
1)摒弃互斥条件
2)摒弃请求保持条件
3)摒弃不剥夺条件
4)摒弃环路等待条件
5)各种方式的比较
5.死锁的避免 熟练掌握银行家算法和安全性检测算法,并能利用这两个算法求解具体问题
6.死锁定理
第二篇:处理机调度与死锁小结
第三章 处理机调度与死锁
重点与难点小结
1.高优先权调度和基于时间片的轮转调度算法
1)高优先权优先调度
2)高响应比优先调度
3)时间片轮转调度
4)多级反馈队列调度
2.常用的几种实时调度算法
1)最早截止时间优先(EDF)算法
2)最低松弛度优先(LLF)算法
3.多处理机环境下的进程(线程)调度方式
1)自调度方式
2)成组调度方式
3)专用处理器分配方式
4.死锁的基本概念
1)产生死锁的原因
2)产生死锁的必要条件
5.预防死锁的方法
1)摒弃互斥条件
2)摒弃请求保持条件
3)摒弃不剥夺条件
4)摒弃环路等待条件
5)各种方式的比较
6.死锁的避免
熟练掌握银行家算法和安全性检测算法,并能利用这两个算法求解具体问题
第三篇:操作系统-课程设计报告-处理机调度程序
操作系统
课程设计报告
学校:广州大学
学院:计算机科学与教育软件学院 班级:计算机127班 课题:处理机调度程序
任课老师:陶文正、陈文彬
姓名:黄俊鹏
学号:1200002111 班内序号:27 成绩:
日期:2015年1月6日
一、设计目的
在多道程序和多任务系统中,系统内同时处于就绪状态的进程可能有若干个。也就是说能运行的进程数大于处理机个数。为了使系统中的进程能有条不紊地工作,必须选用某种调度策略,选择一进程占用处理机。要求学生设计一个模拟处理机调度算法,以巩固和加深处理机调度的概念。
二、设计要求
1)进程调度算法包括:时间片轮转法,短作业优先算法,动态优先级算法。2)可选择进程数量
3)本程序包括三种算法,用C语言实现,执行时在主界面选择算法(可用函数实现)(进程数,运行时间,优先数由随机函数产生)执行,显示结果。
三、设计思路及算法思想
1.界面菜单选项
一级菜单提供2个选项: ① 自动生成进程数量 ② 手动输入所需进程数量
一级菜单选择完毕后进入二级菜单: ① 重新生成进程 ② 时间片轮转法 ③ 短作业优先算法 ④ 动态优先级算法 ⑤ 退出程序
2.调度算法
程序所用PCB结构体
需要用到的进程结构体如上图所示
1)时间片轮转法
主要是设置一个当前时间变量,curTime和时间片roundTime。
遍历进程组的时候,每运行一个进程,就把curTime += roundTime。进程已运行时间加roundTime
2)短作业优先算法
遍历进程组,找到未运行完成并且运行时间最短的进程,让它一次运行完成,如此往复,直到所有进程都运行完成为止。
3)动态优先级算法
做法跟短作业优先算法类似,此处主要是比较进程的优先数,优先级高者,先执行。直到全部执行完毕。当一个进程运行完毕后,适当增减其余进程的优先数,以达到动态调成优先级的效果。
3.程序流程图
四、运行截图
1)启动后输入5,生成5个进程
2)输入1,选择时间片轮转法。
自动输出结果,分别是时间片为1和4的结果
3)输入2,选择短作业优先算法
4)输入3,选择动态优先级算法
5)输入0,重新生成进程,再输入3,生成3个进程,选择2.短作业优先算法
6)输入q,退出
五、心得体会
通过这次实验,让我对操作系统的进程调度有了更进一步的了解。这个实验的模拟程度跟真实系统相比只是冰山一角,由此可见操作系统是何其复杂的软件产品,仅进程调度就有那么丰富和内涵的知识需要掌握。
但是再复杂的系统,都是由小部件构成的。古语云:不积跬步,无以至千里。不积小流,无以成江海。掌握这些基础的知识,可以为以后打下扎实的基础。
六、附录(源代码)
//
// main.c
// ProcessDispatch //
// Created by Jeans on 1/5/15.// Copyright(c)2015 Jeans.All rights reserved.//
#include
//最小进程数
#define MIN_PROCESS //最大进程数
#define MAX_PROCESS
//最小优先数
#define MIN_PRIORITY
0 //最大优先数
#define MAX_PRIORITY
//最小运行时间
#define MIN_RUNNING_TIME
//最大运行时间
#define MAX_RUNNING_TIME
typedef struct PCB{
char name;
//进程名
int priority;
//优先数
int runningTime;
//运行时间
int arriveTime;
//到达时间
int beginTime;
//开始时间
int finishTime;
//完成时间
int cyclingTime;
//周转时间
double weigthCyclingTime;//带权周转时间
int hadRunTime;
//已经运行时间
int finish;
//是否完成 }PCB;//获取随机数
int GetRandomNumber(int min,int max){
return arc4random()%(max-min)+ min;}
//初始化PCB组
void InitPCBGroup(PCB p[],int num){
char name = 'A';
for(int i = 0;i < num;i++){
p[i].name = name;
p[i].priority = GetRandomNumber(MIN_PRIORITY, MAX_PRIORITY);
p[i].runningTime = GetRandomNumber(MIN_RUNNING_TIME,MAX_RUNNING_TIME);
name++;
} }
void PrintResult(PCB p[],int num){
double avgCycTime = 0,avgWeiCycTime = 0;
printf(“|进程名
到达时间
运行时间
开始时间
完成时间
周转时间
带权周转时间
优先数
|n”);
for(int i = 0;i < num;i++){
printf(“|%3c
%-4d
%-4d
%-4d
%-4d
%-4d
%-6.2f
%-4d|n”,p[i].name,p[i].arriveTime,p[i].runningTime,p[i].beginTime,p[i].finishTime,p[i].cyclingTime,p[i].weigthCyclingTime,p[i].priority);
avgCycTime += p[i].cyclingTime;
avgWeiCycTime += p[i].weigthCyclingTime;
//还原
p[i].arriveTime = 0;
p[i].beginTime = 0;
p[i].finishTime = 0;
p[i].cyclingTime = 0;
p[i].weigthCyclingTime = 0;
p[i].hadRunTime = 0;
p[i].finish = 0;
}
avgWeiCycTime /= num;
avgCycTime /= num;
printf(“平均周转时间:%.2f
平均带权周转时间:%.2fn”,avgCycTime,avgWeiCycTime);} //时间片轮转法
void RealRoundRobin(PCB p[],int num,int roundTime){
printf(“nn-----------------------------时间片:%d------n”,roundTime);
int finishNum = 0;
int curTime = 0;
while(finishNum!= num){
for(int i = 0;i < num;i++){
if(p[i].finish)continue;
//开始时间
if(p[i].beginTime == 0 && i!= 0){
p[i].beginTime = curTime;
}
//已经完成
if(p[i].hadRunTime + roundTime >= p[i].runningTime){
p[i].finishTime = curTime + p[i].runningTimep[i].arriveTime;
p[i].weigthCyclingTime = p[i].cyclingTime/(double)p[i].runningTime;
p[i].finish = 1;
finishNum ++;
curTime += p[i].runningTimep[min].arriveTime;
p[min].weigthCyclingTime = p[min].cyclingTime/(double)p[min].runningTime;
p[min].finish = 1;
finishNum++;
curTime = p[min].finishTime;
}
PrintResult(p, num);}
//动态优先级算法
void DynamicPriorityFirst(PCB p[],int num){
printf(“nn-----------------------------动态优先级算法--n”);
int finishNum = 0;
int curTime = 0;
while(finishNum!= num){
int min = 0;
//查找优先级最高下标
for(int i = 1;i < num;i++){
if(p[i].finish == 0 && p[min].priority >= p[i].priority)
min = i;
else if(p[i].finish == 0 && p[min].finish == 1)
min = i;
}
p[min].beginTime = curTime;
p[min].hadRunTime = p[min].runningTime;
p[min].finishTime = p[min].beginTime + p[min].runningTime;
p[min].cyclingTime = p[min].finishTime-p[min].arriveTime;
p[min].weigthCyclingTime = p[min].cyclingTime/(double)p[min].runningTime;
p[min].finish = 1;
finishNum++;
curTime = p[min].finishTime;
}
PrintResult(p, num);}
int main(int argc, const char * argv[]){
PCB pcbGroup[30];
//pcb数组
int processNum = 0;//进程数
while(1){
//选择进程数量
while(1){
if(processNum!= 0)
break;
printf(“n----------n”);
printf(“当前默认进程数范围%d--%dn”,MIN_PROCESS,MAX_PROCESS);
printf(“1)输入0可随机生成进程数目n2)输入%d-%d范围内数字,回车,可生成指定数目进程n>>>>>>”,MIN_PROCESS,MAX_PROCESS);
int num = 0;
scanf(“%d”,&num);
if(num == 0){
processNum = GetRandomNumber(MIN_PROCESS, MAX_PROCESS);
break;
}else{
if((num >= MIN_PROCESS)&&(num <= MAX_PROCESS)){
processNum = num;
InitPCBGroup(pcbGroup,processNum);
break;
}else
printf(“n输入有误,请重新输入.n”);
}
}
//选择算法
printf(“n-----------------------------请输入对应选项序号-----------------------------n”);
printf(“0.重新生成进程 | 1.时间片轮转法 | 2.短作业优先算法 | 3.动态优先级算法 | q.退出n>>>>>>”);
char ch;
while((ch = getchar())== 'n');
switch(ch){
case '0'://0 重新生成进程
processNum = 0;break;
case '1'://1 时间片轮转法
RoundRobin(pcbGroup, processNum);break;
case '2'://2 短作业优先算法
ShortestJobFirst(pcbGroup, processNum);break;
case '3'://3 动态优先级算法
DynamicPriorityFirst(pcbGroup,processNum);break;
case 'q'://q 退出
exit(0);
default:
break;
}
}
return 0;}
第四篇:操作系统 单处理机系统的进程调度
一.实验内容描述
1.目的
(1)了解Windows内存管理器(2)理解Windows的地址过程 2.内容
任意给出一个虚拟地址,通过WinDbg观察相关数据并找到其物理地址
二.理论分析
Windows采用页式虚拟存储管理技术管理内存,页面是硬件级别上的最小保护单位 1.Windows内存管理器
Windows的内存管理主要由Windows执行体中的虚存管理程序负责,并由环境子系统负责,并由环境子系统负责与具体API相关的一些用户态特性的实现。虚存管理程序是Windows中负责内存管理的那些子程序和数据结构的集合 内存管理器的主要任务是:
地址变换:将一个进程的虚拟地址空间转译为物理内存地址
交换:当内存不足时,将内存中的有些内容转移到磁盘上,并且以后还要再次将这些内容读回
2.Windows内存管理策略
Windows采用页式虚拟存储管理技术管理内存,页面是硬件级别上最小的保护单位。根据硬件的体系结构不同,页面尺寸被分为两种,大页面和小页面。X86系统下小页面为4KB,大页面为4MB。大页面的优点是:当引用同一页面内其他数据时,地址转移的速度会很快。不过使用大页面通常要较大的内存空间,而且必须用一个单独的保护项来映射,因此可能会造成出现错误而不引发内存访问违例的情况。通常PC机都为小页面 3.Windows虚拟地址空间布局 x86结构下的布局方式:
默认情况下,32位Windows系统中每个用户进程可以占有2GB的私有地址空间。操作系统占有另外的2GB 2GB用户的进程地址空间布局如表:
2GB的系统地址空间布局如同:
3.虚拟地址转译
地址转译是指将进程的虚拟地址空间映射到实际物理页面的过程。x86系统中地址转译过程如图:
关键数据结构如下: 页目录:每个进程都有一个页目录,它是内存管理器为了映射进程中所有的页表位置而创建的一个页面。进程也目录的地址被保存在内核进程快KPROCESS中,在x86系统上,它被映射到虚拟地址0xC0300000,当一个进程正在执行时,CPU可以通过寄存器CR3知道该进程页目录的位置。页目录由目录项(PDE)构成,每个PDE长4字节,描述了该进程中所有可能的页表的状态和位置。其格式和PTE类似。x86系统上,要描述完整的4GB虚拟地址空间,需要1024个页表。因此映射这些页表的进程页目录需包含1024个PDE,恰好占用一个页面。
页表:进程的页目录项指向页表。每个页表占用一个页面,由1024项PTE组成。一个有效的PTE大小为4字节,包含两个主域:数据所在的物理页面的页面帧编号(PNF)或者内存中一个页面的物理地址的PFN;一些描述该页面状态和保护属性的标志。
虚拟地质结构:x86系统上,一个32位虚拟地址被解释为三个单独的部分,页目录索引、页表索引和字节索引。由于页目录项有1024个,因此页目录索引为10位;一个也表中含有1024个PTE。因此页表索引也为10位,字节索引为12位,正好表示一页(4KB)内容
三.实验步骤及结果
1.查找页目录首地址
以程序WG.exe作为观测对象。
启动WinDbg到内核调试模式,运行程序WG.exe。终断目标机运行,输入命令:kd>!process
发现WG.exe进程正处于运行状态 输入命令:
在KPROCESS中名为DirectoryTableBase的域,对应值为0x9fa6000,即WG.exe进程页目录的物理地址 查看CR3寄存其中的内容,输入命令:
CR3寄存其中的值和KPROCESS中记录的页目录基址相同。这是因为在CPU切换执行任务时,其内容要更新为当前进程的页目录基址。2.地址转译过程
假设给定的虚拟地址为0x401001 输入命令:
可以看到:
PDE的虚拟地址为C0300004.PTE的虚拟地址为C0001004 最后一行信息“pfn 9e4a---DA--UWEV”表示PDE中的具体内容,9e4a是给定虚拟地址所在页表在内存中对应的物理页号,“---DA—UWEV”是标志信息,“pfn a173----A--UREV”表示PTE中的具体内容,a173是数据页装入内存的物理页号。
将数据页对应的物理页号a173加上业内索引(0x1)即可得到虚拟地址0x401001的物理地址
3.观察系统页表
给定观测虚拟地址为0x80001001 输入命令:
当前正在执行的进程是:WG.exe 输入命令:
得到PDE为C0300800,其对应的物理页号为3b 继续让目标机运行,启动A.exe,然后中断目标机运行。输入命令:
当前正在执行的进程为A.exe 输入命令:
PDE信息和对应的物理页号与前面观测到的相同
四.结论
1.数据页对应的物理页号加上相应业内索引即可得到虚拟地址的物理地址 2.不同的进程页目录都指向了相同的系统表页
五.心得体会
在这次上机实验,通过对WinDbg和VPc的调试运用,我熟悉了Windows内存管理器的结构,也认知到Windows如何进行地址转译和转换。对相关的知识也进行了温习,更牢的掌握了相关知识。当然这些还远远不够,我以后还要继续不断努力,去学习了解掌握操作系统的各方面知识。
附录:
1.A.exe代码
#include
#define N 1
HANDLE mutexSemaphore;HANDLE synchSemaphore_1;HANDLE synchSemaphore_2;
HANDLE mutexDisplay;
void Display(char*str,int delayTime){ if(WaitForSingleObject(mutexDisplay,INFINITE)==WAIT_OBJECT_0){ printf(“%snn”,str);ReleaseMutex(mutexDisplay);Sleep(delayTime);} }
void useTime(double limit){ for(double i=0;i<=limit;i+=0.001);}
void CreateProduct(){ Display(“Creating a production...”,0);useTime(200000);Display(“Creating finished.”,100);}
void PutProduct(){ Display(“Putting a production...”,0);useTime(150000);Display(“Putting finished”,100);}
void GetProduct(){ Display(“Getting a production...”,0);useTime(100000);Display(“Getting finished.”,100);}
void ConsumeProduct(){ Display(“Cosuming a production...”,0);useTime(100000);Display(“Cosuming finished.”,100);}
void Producer(){ while(true){ CreateProduct();
if(WaitForSingleObject(synchSemaphore_1,INFINITE)==WAIT_OBJECT_0){
if(WaitForSingleObject(mutexSemaphore,INFINITE)==WAIT_OBJECT_0){ PutProduct();ReleaseSemaphore(mutexSemaphore,1,NULL);} ReleaseSemaphore(synchSemaphore_2,1,NULL);} } }
void Consumer(){ while(true){
if(WaitForSingleObject(synchSemaphore_2,INFINITE)==WAIT_OBJECT_0){
if(WaitForSingleObject(mutexSemaphore,INFINITE)==WAIT_OBJECT_0){ GetProduct();ReleaseSemaphore(mutexSemaphore,1,NULL);} ReleaseSemaphore(synchSemaphore_1,1,NULL);} ConsumeProduct();} }
int main(){ HANDLE thread[2];DWORD threadID[2];
synchSemaphore_1=CreateSemaphore(NULL,N,N,NULL);synchSemaphore_2=CreateSemaphore(NULL,0,N,NULL);mutexSemaphore=CreateSemaphore(NULL,1,1,NULL);
mutexDisplay=CreateMutex(NULL,FALSE,NULL);
printf(“Program start.Please use WinDbg to observe main thread.nPress any key to continue...n”);getchar();
thread[0]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(Producer),NULL,CREATE_SUSPENDED,&threadID[0]);printf(“A producer was created.Please use WinDbg to observe producer thread.nPress any key to continue...n”);getchar();
thread[1]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(Consumer),NULL,CREATE_SUSPENDED,&threadID[1]);printf(“A Consumer was created.Please use WinDbg to observe Consumer thread.nPress any key to continue...n”);getchar();
printf(“Please select:n[1]Make producer thread runn[2]Make Consumer thread runn”);bool flag=true;bool flag_1=true,flag_2=true;int count=0;while(flag){ if(getchar()=='1'&&flag_1){ ResumeThread(thread[0]);count++;flag_1=false;} else if(getchar()=='2'&&flag_2){ ResumeThread(thread[1]);count++;flag_2=false;} if(count==2)flag=false;} WaitForMultipleObjects(1,thread,TRUE,INFINITE);
return 0;}
2.WG.exe代码: #include
int main(){ int a=0;printf(“I'm Wangn”);while(true){a++;} }
第五篇:生产调度小结
作为计划调度,时刻都要按计划要求注意产品的流动状态。铸造作为产品的始端,是否能够按计划完成客户订单起着极其重要的地位。因此每天要到铸造车间巡视3—4次,监督重力和低压是否按计划进行生产,对于即将发货的型号要及时督促完成,以免影响发货。在查看铸造型号时,有的铸件型号刻于零件的外圈,有的位于内边缘。还可以从轮毂的辐条上得到型号(模具号+规格)。
机加作为对毛坯的处理阶段,要关注每天所加工的型号是否按计划正常进行,对于发现的问题要及时告知,若有不改者及时通知其部门负责人。在机加车间巡视时不仅要关注即将发货的型号,还要注意已加工完成还未及时转入下个工序的产品。若出现这类情况告知有关人员并及时清理。一旦出现问题机加责任重大,自身疏忽监督也难辞其咎,所以,要全面的,认真对待自己的工作,不得有半点马虎。在机加巡视时,留心学习各个车轮型号,要达到当看见轮子时就能知道它属于什么模具类型和尺寸大小
做事要有主次,有轻重,有责任,每天要有一个清醒的任务,今天要完成什么,或者什么该加紧完成,对于即将出货的订单型号要及时去铸造、机加、涂装巡视产品归于何处并告知相关人员及时将此类型号的产品抓紧完成。