操作系统实验二(调度算法模拟-先进先出-时间片轮转法-优先服务调度算法)

Posted JINKELA_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了操作系统实验二(调度算法模拟-先进先出-时间片轮转法-优先服务调度算法)相关的知识,希望对你有一定的参考价值。

实验二 进程调度

一、     实验目的

1.       理解进程运行的并发性。 

2.       理解处理器的三级调度。

3.       掌握先来先服务的进程调度算法。

4.       掌握短进程优先的进程调度算法。

5.       掌握时间片轮转的进程调度算法。 

二、     实验设备

1.     安装windows或者linux操作系统的PC机

2.     C程序编译环境

三、     实验内容

用c语言编程模拟实现至少一个操作系统的常见进程调度算法。常见的进程调度算法有先来先服务、短进程优先、时间片轮转法等。

四、     实验要求

1.     上机编写并调试进程调度的模拟程序。

2.     要把相应的程序代码及程序运行结果写入实验报告中。

 

//操作系统—进制控制模拟
#include<stdio.h>
#include<stdlib.h>
#include <windows.h>
#include<tlhelp32.h>
#define N 10
struct pb
{
  int ko;
  int no;
  int cha;
};
typedef struct pb PCB;
PCB a[N];
int showallproc()
{
    PROCESSENTRY32 pe32;//用来存储进程信息的结构体
    pe32.dwSize=sizeof(pe32);
    HANDLE hProcessSnap=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);//获取进程快照
    if(hProcessSnap==INVALID_HANDLE_VALUE)
    {
        printf("调用失败\n");
        return 1;
    }
    BOOL bProc=Process32First(hProcessSnap,&pe32);
    while(bProc)
    {
        printf("%5d %s\n",pe32.th32ProcessID,pe32.szExeFile);//输出进程ID和进程名
        bProc=Process32Next(hProcessSnap,&pe32);
    }
    CloseHandle(hProcessSnap);
    return 0;
}
static int count=1;
void create()   //创建
{
  static int pi=1;
  int k,l=0,m;
  printf("请输入创建的进程号:");
  scanf("%d",&m);
  for(k= 1;k<= N;k++ )
    if(a[k].no ==m)
	  l=1;
	if(l == 1)
	{
	  printf("错误,进程创建重复!\n");
	  create();
	}
    else
	{
		for(k= 1;k<= N;k++ )
		{
			if(a[k].no==0)
			{
				pi=k;break;}
		}
	  a[pi].no=m;
	  printf("\n输入优先级:");
	  scanf("%d",&a[pi].ko);
	  if(count>1)            //首次进程状态为执行,之后为活动就绪
	    a[pi++].cha=3;
	  else
	    a[pi++].cha=5;
	  count++;
	}
}

int stopproc()
{
    DWORD ProcessID;
    printf("请输入想要终止的进程ID\n");
    scanf(" %d",&ProcessID);
    HANDLE hProcess=OpenProcess(PROCESS_TERMINATE,FALSE,ProcessID);//打开对应进程句柄
    if (hProcess==NULL)
    {
        printf("失败\n");
        return -1;
    }
    if (!TerminateProcess(hProcess,0))//关闭进程
    {
        printf("关闭失败\n");
    }
    else
    {
        printf("关闭成功\n");
    }
    CloseHandle(hProcess);
    
    return 0;
}

void dispatch()   //调度
{
	int i,m,l=0,j=0,k,min=10000;

	for(m= 1;m<= N;m++ )
		if(a[m].cha==5)
			l=m;
		if(l!=0)
		{
			printf("调度失败!");
			return;
		}
		else 
	for(k= 1;k<= N;k++ )
	{
		if(a[k].cha==3)
		if(min>a[k].ko)
		{
			min=a[k].ko;
		    i=k;
			j=1;
		}
	}
	    if(j)         
		    a[i].cha=5;
        else if(j==0)
			printf("调度失败!\n");
	
}

void block()   //阻塞
{
  int k,m,l=0;
  printf("请输入已经创建的进程号:");
  scanf("%d",&m);
  for(k= 1;k<= N;k++ )
    if(a[k].no==m)
	  l=k;
	if(l!=0)
	{
	  if(a[l].cha==3 || 5)
	    a[l].cha=4;
		else if(a[l].cha==1)
		  a[l].cha=2;
		  else
		  printf("阻塞失败!\n");
	}
	else
		printf("阻塞失败!");
}

void wakeup()   //唤醒
{
  int k,m,l=0;
  printf("请输入已经创建的进程号:");
  scanf("%d",&m);
  for(k= 1;k<= N;k++ )
   if(a[k].no==m)
     l=k;
   if(l!=0)
   {
	 if(a[l].cha==2)
	   a[l].cha=1;
	   else if(a[l].cha==4)
	     a[l].cha=3;
	     else
		 printf("唤醒失败!\n");
   }
   else
	   printf("唤醒失败!");
}


void suspend()   //挂起
{
  int k,m,l=0;
  printf("请输入已经创建的进程号:");
  scanf("%d",&m);
  for(k= 1;k<= N;k++ )
    if(a[k].no==m)
	  l=k;
	if(l!=0)
	{
	  if(a[l].cha==3 || 5)
	    a[l].cha=1;
		else if(a[l].cha==4)
		  a[l].cha=2;
		  else
		  printf("错误!挂起失败\n");
	}
	else
		printf("错误!挂起失败!");
}

void active()   //激活
{
  int k,m,l=0;
  printf("请输入已经创建的进程号:");
  scanf("%d",&m);
  for(k= 1;k<= N;k++ )
    if(a[k].no==m)
	  l=k;
	if(l!=0)
	{
	  if(a[l].cha==1)
	    a[l].cha=3;
		else if(a[l].cha==2)
		  a[l].cha=4;
		  else
		  printf("激活失败!\n");
	}
	else 
		printf("激活失败!");
}

void display()   //查看PCB功能模块
{
  int i; 
  printf("\t\tPCB\t进程号\t优先级\t状态\n");
  for(i= 1;i<= 10;i++ )
  printf("\t\t%d\t%d\t%d\t%d\n",i,a[i].no,a[i].ko,a[i].cha);
  printf("\t1-静止就绪  2--静止阻塞  3--活动就绪  4--活动阻塞  5--执行\n");
}

void change_KO()   //改变优先数
{
  int k,m,l=0;
  printf("请输入已创建的进程号:");
  scanf("%d",&m);
  for(k= 1;k<= N;k++ )
    if(a[k].no==m)
	  l=k;
    if(l!=0)
	{
	    printf("输入新的优先级:");
	    scanf("%d",&a[l].ko);
	    display();
	}
	else
		printf("失败!");
}
/********************这是先来先服务的程序*********************************/
struct fcfs{//定义先来先服务结构体、参数
char name[10];
float daodatime;//到达时间
float fuwutime;//服务时间
float kaishitime;//开始时间
float wanchengtime;//完成时间
float zhouztime;//周转时间
float daiquantime;//带权周转时间
};
fcfs b[10000];
void input(fcfs *p,int N1)  //构造一个输入进程的信息的函数,定义结构体指针
{ 
	int i;   
   for(i=0;i<=N1-1;i++)
   {
     printf("输入第%d个进程的名字、到达时间、服务时间:\n",i+1);
     scanf("%s%f%f",&p[i].name,&p[i].daodatime,&p[i].fuwutime);//把输入的信息保存到结构体指针所对应的内存中
   }

}//构造一个输出函数
void Print(fcfs *p,float daodatime,float fuwutime,float kaishitime,float wanchengtime,float zhouztime,float daiquantime,int N1)
{
	int k;
    printf("执行顺序:\n");
    printf("%s",p[0].name);
    for(k=1;k<N1;k++)
	{
		printf("-->%s",p[k].name);
	}
     printf("\n进程的相关信息如下:\n");
     printf("\n名字\t到达\t服务\t开始\t完成\t周转\t带权周转\n");
     for(k=0;k<=N1-1;k++)
	 { 
      printf("%s\t%-.2f\t%-.2f\t%-.2f\t%-.2f\t%-.2f\t%-.2f\t\n",p[k].name,p[k].daodatime,p[k].fuwutime,p[k].kaishitime,p[k].wanchengtime,p[k].zhouztime,p[k].daiquantime);
	 } //题目中加入-.2是保留双精度的两位。一般f默认保留六位小数的。  
} 
  void sort(fcfs *p,int N1)//进程根据到达时间进行排序
  { 
     for(int i=0;i<=N1-1;i++)
      for(int j=0;j<=i;j++)
       if(p[i].daodatime<p[j].daodatime)//如果i的时间到达时间小于j的到达时间,就交换
	   {
         fcfs temp;//在结构体中定义第三个变量进行交换
         temp=p[i];
         p[i]=p[j];
         p[j]=temp;
	   }
}
//核心的运行阶段
void deal(fcfs *p, float daodatime,float fuwutime,float kaishitime,float wanchengtime,float zhouztime,float daiquantime,int N1)
{ int k;
    for(k=0;k<=N1-1;k++)
	{
	  if(k==0)//K=0,表示第一个进程到达
	  { 
       p[k].kaishitime=p[k].daodatime;//那么开始时间=到达时间
       p[k].wanchengtime=p[k].daodatime+p[k].fuwutime;//完成时间=到达时间+服务时间
	  }
         else
		 {
           p[k].kaishitime=p[k-1].wanchengtime;//下一个进程的开始时间=上一个进程的完成时间
           p[k].wanchengtime=p[k-1].wanchengtime+p[k].fuwutime;//完成时间=上一个进程的完成时间+服务时间
		 }
	}
     for(k=0;k<=N1-1;k++)//计算周转时间和带权周转时间
     { 
      p[k].zhouztime=p[k].wanchengtime-p[k].daodatime;//周转时间=完成时间-到达时间
      p[k].daiquantime=p[k].zhouztime/p[k].fuwutime;//带权周转时间=周转时间/服务时间   
	 }
}
void FCFS(fcfs *p,int N1)//定义先来先服务函数
{  
     float daodatime=0,fuwutime=0,kaishitime=0,wanchengtime=0,zhouztime=0,daiquantime=0;//初始化变量为0
     sort(p,N1);//声明排序函数
     deal(p,daodatime,fuwutime,kaishitime,wanchengtime,zhouztime,daiquantime,N1);//声明运行函数
     Print(p,daodatime,fuwutime,kaishitime,wanchengtime,zhouztime,daiquantime,N1); //声明输出函数
}
/****************************这是优先服务调度算法的代码***********************************/
typedef struct PCB2
{  
   char name[10];//进程名
   int runtime;//要求运行时间
   int frist;//定义优先数
   char zhuangtai; //定义状态,R为就绪,F为完成
};
struct PCB2 PCBcontrol[4];//定义进程控制块数组 
void youxian()//构造优先函数 
{
	int i,n;
	printf("请输入进程的个数:\n");
    scanf("%d",&n);
	printf("请输入进程的名字、优先权、运行时间\n");
	printf("\n");
	for(i=0;i<n;i++)
	{
		printf("请输入第%d个进程的信息:\n",i+1);
		scanf("%s%d%d",&PCBcontrol[i].name,&PCBcontrol[i].frist,&PCBcontrol[i].runtime);
        PCBcontrol[i].zhuangtai='R';//进程初始状态均为就绪
        getchar();//等待回车进入下一次运行
	} 
} 
  int max_frist_process()//确定最大优先级进程子程序 
  { 
     int max=-10;//max为最大优先数,初始化为-10  
     int i,key;  
     for(i=0;i<3;i++) 
	 {
		 if(PCBcontrol[i].zhuangtai=='r')//r表示正在运行
			 return -1;//返回-1
		 else
			 if(max<PCBcontrol[i].frist&&PCBcontrol[i].zhuangtai=='R')//从就绪进程中选取优先数最大的进程
			 {
				 max=PCBcontrol[i].frist;//max存放每次循环中的最大优先数
				 key=i;//将进程号赋给key
			 }
	 }
	 if(PCBcontrol[key].zhuangtai=='F')//具有最大优先数的进程若已运行完毕
		 return -1;//则返回-1
	 else
		 return key;//将key作为返回值返回 
  }
  void show()//显示函数
  {
	  int i;  
      printf("\n进程名  优先级 运行时间 当前状态\n");
	  printf("*****************************************\n");
      for(i=0;i<3;i++)//依次显示每个进程的名、优先数、要求运行时间和状态
	  {
		  printf("  %s\t %d\t  %d\t   %s\t\n",&PCBcontrol[i].name,PCBcontrol[i].frist,PCBcontrol[i].runtime,&PCBcontrol[i].zhuangtai); 
	  }
	   printf("\n请按回车键进行查看");
  }
  void run()//进程运行子程序
  {
	  int i,j;
	  int t=0;//t为运行次数
	  for(j=0;j<3;j++)
	  {
		  t+=PCBcontrol[j].runtime;}//运行次数即为各个进程运行时间之和 
          printf("\n进程没运行前,当前的状态是:\n");  
          show(); //调用show()子程序显示运行前PCB的情况
		  getchar();//等待回车进入下一次运行
		  for(j=0;j<t;j++) 
		  {
			  while(max_frist_process()!=-1)//具有最大优先数的进程没有运行完,让其运行
			  {
				  PCBcontrol[max_frist_process()].zhuangtai='r';//将其状态置为r,表示其正在运行
			  }
			  for(i=0;i<3;i++)
			  {
				  if(PCBcontrol[i].zhuangtai=='r')
				  {
					  PCBcontrol[i].frist-=1;//将当前运行进程的优先数减1
					  PCBcontrol[i].runtime--;//要求运行时间减1
					  {
						  if(PCBcontrol[i].runtime==0)
							  PCBcontrol[i].zhuangtai='F';//运行完则将该进程状态置为结束
						  else
							  PCBcontrol[i].zhuangtai='R';//未运行完将其状态置为就绪
					  }
					  show();//显示每次运行后各PCB的情况
					  getchar();//等待回车进入下一次运行
				  }  
			  } 
		  } 
  }
  /***********************这是算法时间片轮转法的代码*****************************************/
  struct shijian {//定义时间片的结构体
	char name;  //定义进程名
    int daodatime;// 到达时间
    int fuwutime;  //服务时间
    int shengyutime;//剩余时间
	char *state;//所处状态
	struct shijian *next;
};
struct shijian *time()
{
	int a,i;
	struct shijian *head, *rear,*p,*q,*t;//定义队首、队尾、P是队尾指针、Q是队首指针和执行时间
	head=rear=NULL;//初始化队首和队尾为空 
    printf("请输入进程数目:");  
    scanf("%d",&a); 
	for(i=0;i<a;i++)
	{
		p=(struct shijian*)malloc(sizeof(struct shijian)); //初始化一个空间给进程进入
		printf("输入第%d个进程的名字、到达时间、服务时间:\n",i+1);
        scanf("%s%d%d",&p->name,&p->daodatime,&p->fuwutime);  
        p->shengyutime=p->fuwutime; 
        p->state="就绪";            
        if(rear==NULL) //当输入结束时,把P的数据放到队首,以便执行下一步
		{
			head=p;   
            p->next=NULL;   
            rear=p;  
		}
		else  //否则执行时间就为空,队首变成Q
		{
			t=NULL;   
            q=head;
			while(q&&q->daodatime<p->daodatime)//当Q和Q的到达时间小于P的到达时间时,把执行时间给Q
			{
				t=q;      
                q=q->next;
			}
			if(q==head)  //而当Q是队首时,则下一个队首变成P,以便每个进程都能够得到时间片
			{
				p->next=head;  
                head=p;
			}
			else if(t==rear)  //当执行时间片到达队尾时(执行完时),返回给队首P
			{
				rear->next=p; 
                p->next=NULL; 
                rear=p;
			}
			else   //否则给队首P占用执行时间,P执行完后到Q
			{
				t->next=p;   
                p->next=q;
			}   
		}   
	}
	return head;//返回队首
}
void output(struct shijian *head)//定义输出函数
{
	struct shijian *p,*t,*r; 
    int num;  
    printf("请输入时间片:");  
    scanf("%d",&num);
	while(head!=NULL) //当队首不为空时,把P给队首
	{
		r=p=head;
		while(p!=NULL) //把执行时间给队首
		{
			t=head;  
            p->shengyutime=p->shengyutime-num;  //P的剩余时间=剩余时间-时间片
            p->state="运行"; //状态变成运行态
            if(p->shengyutime<0) //当P运行完,即剩余时间小于0时,仍然把它当做0处理
            p->shengyutime=0;  
            printf("\n************程序开始运行*****************\n");
            printf("进程  到达时间 服务时间  剩余时间  当前状态\n");
			while(t!=NULL)  //时间不为空时,输出当前进程的信息,并把时间片交给下一个进程
			{
				printf("%2c%8d%8d%14d%10s\n",t->name,t->daodatime,t->fuwutime,t->shengyutime,t->state);  
                t=t->next;
			}
			getchar(); //按住回车键观看
			if(p->shengyutime==0)//当队首的剩余时间为0时,先把队首改成P的下一个,然后释放内存,删除队首节点
			{
				if(p==head)
				{
					head=p->next;
		            free(p);
		            p=head;
				}
				else  //否则返回执行,把队尾的下一个指针变成P的下一个指针,队尾的位置移动到队首
				{
					r->next=p->next; 
                    p=r->next; 
                    r=p;
				} 
			}
			else  //否则把队首的位置给队尾,把队首的状态显示为"就绪"状态
			{
				r=p;
				p->state="就绪";    
                p=p->next; 
			} 
		}   
    } 
}  
void diaodusuanfa()
{
	int N1;
	  int number;
	  char Tishikuang;//提示框
	  do{
        printf("    **                       输入 1-先来先服务                           *\n");
        printf("    **                       输入 2-时间片轮转法                         *\n");
        printf("    **                       输入 3-优先服务法                           *\n");
        printf("    **                       输入 0-退出该程序                           *\n");
        printf("\n提示:请根据自己的需求选择相应的操作数:\n");
        scanf("%d",&number);/*提示输入字母,用switch语句存入到case中,最后增加提示框是否继续*/
        switch(number)
        {
        case 0:
           break;
        case 1:
             printf("您选择的是**先来先服务调度**\n\n");
		     printf("请输入进程的数量:\n");
             scanf("%d",&N1);
             input(b,N1);
             FCFS(b,N1);
            break;
        case 2:
			printf("\n您选择的是时间片轮转发调度\n\n");
			struct shijian *head; //定义时间片的队首结构体
            head=time(); //队首执行的时间
            output(head) ;//输出函数
            break;
        case 3:
			printf("\n您选择的是优先服务调度,本程序可提供3个进程的调度。\n\n");
		    youxian();//初始化各个进程PCB 
            run();//进程调度模拟
		   break;
        default:
            printf("\n你的输入有误,请确定是从0到3之间进行输入,O(∩_∩)O谢谢\n");
            break;
        }
        printf("\n是否继续操作(y/n) ?");
        fflush(stdin);
        Tishikuang=getchar();
	}while(Tishikuang=='y'||Tishikuang=='Y');
} 

int main()
{
  int i;

  do
  {
   	printf("\t\t**************功能模块 ***************\n");
    printf("\t\t*        1-----进程创建             *\n");
    printf("\t\t*        2-----进程撤消             *\n");
    printf("\t\t*        3-----调度                 *\n");
	printf("\t\t*        4-----阻塞                 *\n");
    printf("\t\t*        5-----唤醒                 *\n");
    printf("\t\t*        6-----挂起                 *\n");
    printf("\t\t*        7-----激活                 *\n");
    printf("\t\t*        8-----查看进程控制块       *\n");
    printf("\t\t*        9-----改变优先数           *\n");
    printf("\t\t*       10----查看进程              *\n");
    printf("\t\t*       11----调度算法模拟          *\n");
    printf("\t\t*        0-----退出                 *\n");
    printf("\t\t*************************************\n");
    printf("\t\t请选择0-10:");
    scanf("%d",&i);
    printf("\n");
    switch(i)
    {
      case 1: create();break;
	  case 2:stopproc();break; 
	  case 3: dispatch();break;
	  case 4: block();break;
	  case 5: wakeup();break;
	  case 6: suspend();break;
	  case 7: active();break;
	  case 8: display();break;
	  case 9: change_KO();break;
      case 10: showallproc();break;
      case 11: diaodusuanfa();break;
	  case 0: exit(0);   //程序正常退出
    }
  }
  while(i!=0);
}

以上是关于操作系统实验二(调度算法模拟-先进先出-时间片轮转法-优先服务调度算法)的主要内容,如果未能解决你的问题,请参考以下文章

时间片轮转算法和优先级调度算法模拟实现

时间片轮转算法和优先级调度算法 C语言模拟实现

进程调度算法

OS(A)之进程调度模拟算法

操作系统进程

操作系统进程