操作系统实验调度

360 阅读10分钟

操作系统实验(进程调度)

一、实验目的

二、实验内容

三、实验准备

3.1优先权算法

3.2时间片轮转调度算法

四、实验

一、实验目的

  1.1理解有关进程控制块、进程队列的概念。

  1.2掌握进程优先权调度算法和时间片轮转调度算法的处理逻辑。

二、实验内容

  2.1设计进程控制块PCB的结构,分别适用于优先权调度算法和时间片轮转调度算法。

  2.2建立进程就绪队列。

  2.3编制两种进程调度算法:优先权调度和时间片轮转调度。

三、实验准备

3.1优先权算法

  为了照顾紧迫型进程获得优先处理,引入了优先权调度算法。它从就绪队列中选择一个优先权最高的进程,让其获得处理器并执行。这时,又进一步把该算法分为两种方式。

3.1.1非抢占式优先权调度算法。

  在这种方式下,系统一旦把处理器分配给就绪队列中优先权最高的进程后,该进程就占有处理器一直运行下去,直到该进程完成或因发生事件而阻塞,才退出处理器。系统这时才能将处理器分配给另一个优先权高的进程。这种方式实际上是每次将处理器分配给当前就绪队列中优先权最高的进程。它常用于批处理系统中,也可用于某些对时间要求不严格的实时系统中。

3.1.2抢占式优先权调度算法。

  在这种方式下,系统同样把处理器分配给当前就绪队列中优先权最高的进程,使之执行。但在其执行期间,仍然会不断有新的就绪进程进入就绪队列,如果出现某个进程,其优先权比当前正在执行的进程的优先权还高时,进程调度程序就会立即暂停当前进程的执行而将处理器收回,并将处理器分配给新出现的优先权更高的进程,让其执行,这种方式实际上水远都是系统中优先权最高的进程占用处理器执行。因此,它能更好地满足紧迫进程的要求,故常用于要求比较严格的实时系统中,以及对性能要求较高的批处理和分时系统中。

  对于优先权调度算法,其关键在于是采用静态优先权,还是动态优先权,以及如何确定进程的优先权。

静态优先权:

  是在创建进程时确定的,并且规定它在进程的整个运行期间保持不变。一般来说,优先权是利用某个范围内的一个整数来表示的、如0~7,或0~255中的某个整数,所以又称为优先数。在使用时,有的系统用“0”表示最高优先权,数值越大优先权越小,而有的系统则恰恰相反。

动态优先权

  要配合抢占调度方式使用,它是指在创建进程时所赋予的优先权,可以随着进程的推进而发生改变,以便获得更好的调度性能。在就绪队列中等待调度的进程,可以随着其等待时间的增加,其优先权也以某个速率增加。因此,对于优先权初值很低的进程,在等待足够长的时间后,其优先权也可能升为最高,从而获得调度,占用处理器并执行。同样规定正在执行的进程,其优先权将随着执行时间的增加而逐渐降低,使其优先权可能不再是最高,从而暂停其执行,将处理器回收并分配给其他优先权更高的进程。这种方式能防止个别长期进程长期占用处理器的现象。

3.2时间片轮转调度算法

  在分时系统中,为了保证人机交互的及时性,系统使每个进程依次按时间片方式轮流地执行,即时间片轮转调度算法。在该算法中,系统将所有的就绪进程按进入就绪队列的先后次序排列。每次调度时把CPU分配给队首进程,让其执行一个时间片,当时间片用完,由计时器发出时钟中断,调度程序则暂停该进程的执行,使其退出处理器,并将它送到就绪队列的末尾,等待下一轮调度执行。然后,把CPU分配给就绪队列中新的队首进程,同时也让它执行一个时间片。这样就可以保证就绪队列中的所有进程,在一定的时间(可接受的等待时间)内,均能获得一个时间片的执行时间。   在时间片轮转调度算法中,时间片的大小对系统的性能有很大影响。如果时间片太大,大到每个进程都能在一个时间片内执行结東,则时间片轮转调度算法退化为先来先服务调度算法,用户将不能获得满意的响应时间。若时间片过小,连用户键入的简单常用命令都要花费多个时间片,那么系统将频繁地进行进程的切换,同样难以保证用户对响应时间的要求。

四、实验

  1.同学们必须独立完成程序的调试和运行,记录运行结果并对结果进行分析;

  2.分析程序所定义使用的数据结构;

  3.分析程序的结构,并画出程序流程图;

  4.撰写分析报告

4.2数据类型定义:

1.1	数据结构
\#include\<conio.h>//getch函数输出
\#define PSUM 3//进程数为3
\#define PTIME 30//进程时间为30

enum process\_state
{
ready,//就绪状态
execute,//执行状态
finish//完成状态
};//定义进程状态

struct lskpcb
{
char name\[4];//进程名
int priority;//优先权
int cputime;//CPU运行时间
int needtime;//进程运行所需时间
int count;//进程执行次数
int round;//时间片轮转轮次
int process;//进程状态
struct lskpcb \*next;//创建一个指针
};// 定义进程创建的PCB

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
4.3 程序流程图如下图:

优先权流程图如下:

时间片轮转调度法程序流程图如下:

完整代码如下:

\#include\<stdio.h>
\#include\<conio.h>//getch函数输出
\#include\<stdlib.h>
\#include<iostream>
\#include\<windows.h>
\#define PSUM 3//进程数为3
\#define PTIME 30//进程时间为30

enum process\_state
{
ready,//就绪状态
execute,//执行状态
finish//完成状态
};//定义进程状态

struct lskpcb
{
char name\[4];//进程名
int priority;//优先权
int cputime;//CPU运行时间
int needtime;//进程运行所需时间
int count;//进程执行次数
int round;//时间片轮转轮次
int process;//进程状态
struct lskpcb \*next;//创建一个指针
};// 定义进程创建的PCB

lskpcb \*get\_process()
{
lskpcb \*q;
lskpcb \*t;
lskpcb \*p;
int i = 0;
printf("请输入进程名和cpu运行时间:\n");

    while(i < PSUM)
    {
    	q=(struct lskpcb *)malloc(sizeof(struct lskpcb));
    	scanf("%s", &(q -> name));
    	scanf("%d", &(q -> needtime));
    	q -> cputime = 0;
    	q -> priority = PTIME - q -> needtime;
    	q -> process = ready;
    	q -> next = NULL;//指针默认值为空 
    	
    	if(i == 0)
    	{
    		p = q;
    		t = q;
    	}
    	else
    	{
    		t -> next = q;//创建就绪进程队列
    		t = q;
    	}
    	i++;
    }//输入模拟测试的进程名和执行所需时间,初始设置可模拟5个进程的调度	
    return p;

}

void display(struct lskpcb \*p)
{
printf("进程名""   ""cpu运行的时间""   ""还需要的时间""   " "优先权""   ""状态\n");

    while(p)
    {
    	printf("%s",p -> name); 
    	printf("            ");
    	printf("%d",p -> cputime);
    	printf("               ");
    	printf("%d",p -> needtime);
    	printf("            ");
    	printf("%d",p -> priority);
    	printf("     ");

    switch(p -> process)//进程状态循环 
    {
    	case ready:
    	printf("就绪\n",ready);
    	break;
    	case execute:
    	printf("执行\n",execute);
    	break;
    	case finish:
    	printf("完成\n",finish);
    	break;
    }
    p = p->next;
    }//显示模拟结果,包含进程名、CPU时间、运行所需时间以及优先级

}

int process\_finish(lskpcb \*q)
{
int ks = 1;
while(ks && q)
{
ks = ks && q -> needtime == 0;
q = q -> next;
}
return ks;
}//结束进程,即将队列中各进程的所需时间设置为0

void cpuexe(lskpcb \*q)
{
lskpcb \*t = q;
int tp = 0;

    while(q)
    {
    	if(q -> process != finish)
    	{
    		q -> process = ready;	
    	}
    	if(q -> needtime == 0)
    	{
    		q -> process = finish;
    	}
    	if(tp < q -> priority && q -> process != finish)
    	{
    		tp = q -> priority;
    		t = q;
    	}
    	q = q -> next;
    }
    if(t -> needtime != 0)
    {
    t -> priority -= 2;
    t -> needtime --;
    t -> process = execute;
    t -> cputime ++;
    }

}//选择某一进程,给它分配CPU
//计算进程优先级

void priority\_cal()
{
lskpcb \*p;
system("cls");//清屏函数
p = get\_process();
int cpu = 0;
system("cls");

    while(!process_finish(p))
    {
    	cpu++;
    	printf("CPU运行时间:%d\n",cpu);
    	cpuexe(p);
    	display(p);
    	getch();
    	system("cls");
    }
    printf("全部优先权进程已运行完毕,请输入学号退出演示或者任意键进入主菜单选择界面:\n");
    getch();
    system("cls");

}

void displaymenu()
{
printf("******程序只用于模拟测试******\n");
printf("请使用者选择以下功能菜单:\n");
printf("1.时间片轮法\n");
printf("2.优先权调度\n");
printf("3.退出请输入正确的指令:\n");
}//显示调度算法菜单,可供用户选择优先权调度算法和时间片轮转调度算法

lskpcb \*getprocess\_round()
{
lskpcb \*q;
lskpcb \*t;
lskpcb \*p;
int i = 0;
printf("请输入进程名和时间\n");

    while(i<PSUM)
    {
    	q = (struct lskpcb * )malloc(sizeof(struct lskpcb));
    	scanf("%s", &(q->name));
    	scanf("%d", &(q->needtime));
    	q -> cputime = 0;
    	q -> round = 0;
    	q -> count = 0;
    	q -> process = ready;
    	q -> next = NULL;
    	
    	if(i == 0)
    	{
    		p = q;
    		t = q;
    	}
    	else
    	{
    		t -> next = q;
    		t = q;
    	}
    	i++;
    }
    return p;

}//时间片轮转调度算法创建就绪进程队列

void cpu\_round(lskpcb \*q)
{
q -> cputime += 1;//CPU时间加2
q -> needtime -= 1;//还需要的时间减2

    if(q -> needtime < 0)
    {
    	q-> needtime = 0;
    }
    q -> count ++;
    q -> round ++;
    q -> process = execute;

}//采用时间片轮转调度算法执行某一进程

lskpcb \*get\_next(lskpcb \*L,lskpcb \*H)
{
lskpcb \*t;
t = L;
do
{
t = t->next;
}

    while(t && t -> process == finish);
    if(t == NULL)
    {
    	t = H;
    	while(t -> next != L && t -> process == finish)
    	{
    		t = t-> next;
    	}
    }
    return t;

}//获取下一个进程

void setstate(lskpcb \*p)
{
while(p)
{
if(p -> needtime ==  0)
{
p -> process = finish;//如果所需执行时间为0,则设置运行状态为结東
}
if(p -> process == execute)
{
p -> process = ready;//如果为执行状态则设置为就绪
}
p = p -> next;
}
}//设置队列中进程执行状态

void display\_round(lskpcb \*p)
{
printf("进程名" "   " "CPU运行时间" "   " "还需要的时间" "   " "时间片的次数" "   " "时间片进程轮次" "   " "状态\n");

    while(p)
    {
    	printf("%s", p -> name);
    	printf("           ");
    	printf("%d", p -> cputime);
    	printf("                ");
    	printf("%d", p -> needtime);
    	printf("             ");
    	printf("%d",p -> count);
    	printf("               ");
    	printf("%d",p -> round);
    	printf("          ");
    	
    	switch(p -> process)
    	{
    		case ready:
    		printf("就绪\n",ready);
    		break;
    		case execute:
    		printf("执行\n",execute);
    		break;
    		case finish:
    		printf("完成\n",finish);
    		break;
    	}
    	p  =  p -> next;
    }

}//时间片轮转调度算法输出调度信息

void round\_cal()
{
lskpcb \*p;
lskpcb \*r;
system("cls");
p = getprocess\_round();
int cpu = 0;
system("cls");
r = p;

    while(!process_finish(p))
    {
    	cpu += 1;
    	cpu_round(r);
    	r = get_next(r,p);
    	printf("CPU运行时间:%d\n",cpu) ;
    	display_round(p);
    	setstate(p);
    	getch();
    	system("cls");
    }
    printf("全部时间片进程已运行完毕,请输入任意键进入主菜单选择界面:\n");
    getch();//等待读取键盘字符 
    system("cls");

}//时间片轮转调度算法计算轮次及输出调度信息

int main()
{
displaymenu();

    while(true)
    {
    	int lsp = 0;
    	int flag = 0;
    	scanf("%d",&lsp);
    	
    	switch(lsp)
    	{
    		case 1:
    		round_cal();
    		break;
    		case 2:
    		priority_cal();
    		break;
    		case 3:
    			{
    				printf("警告!!!!退出系统错误,需要输入正确的指令退出系统请重新输入:\n") ;
    				break;
    			}
    		case 49:
    		{
    			flag = 1;
    			break;
    		}//退出系统的代码,当输入49口令时能正确退出系统 
    		default:
    				break;
    	}
    	if(flag == 1)
    	{
    		break;
    	}//当flag=1时跳出循环进入菜单选择模式 
    	displaymenu(); 
    }

}