Operating system process scheduling algorithm - first come first served, time slice rotation, priority scheduling algorithm

1. First come first serve scheduling algorithm

(1) Algorithm content: The first-come-first-serve scheduling algorithm is the simplest scheduling algorithm, which can be applied to both high-level scheduling and low-level scheduling. In advanced scheduling, the FCFS scheduling algorithm selects jobs to enter the memory according to the order in which they enter the backup job queue, that is, the jobs that enter the backup job queue first are first selected to enter the memory, and then create a process for the selected job and allocate the resources required by the job. In low-level scheduling, the FCFS scheduling algorithm selects a first-entry process/thread from the memory process/thread ready queue each time, and then the process/thread scheduler assigns the CPU to it and makes it run.

(2) Algorithm requirements: each process is represented by a process control block (PCB). The process control block can contain the following information: process name, arrival time, running time, start time, completion time, waiting time, turnaround time, delegation turnaround time, etc. The process that enters the ready queue first will be assigned a processor to run first. Once a process takes possession of a processor, it continues to run until the process finishes its work or is unable to continue running because it is waiting for an event to occur before releasing the processor.

(3) Design idea: The algorithm is executed in the order of the arrival time of the processes, and the ones that arrive first are executed first.

(4) Algorithm analysis: first define a PCB structure;

Define the input() input function, input the process number, arrival time, and running time;

Define the output() output function to output various times of each process block;

Define the rank() sorting function to sort the processes according to their arrival time;

Define FCFS () first-come-first-serve algorithm function to calculate various times;

Define the main() main function to realize the first-come-first-served function;

(5) Core code:

#include<stdio.h>
    double atime;            //平均周转时间 
	double awtime;    //平均带权周转时间
struct PCB     //声明结构体类型PCB 
{
	char name[20];          //进程号 
	int arrivaltime;       //到达时间 
	int runtime;           //运行时间 
	int starttime;         //开始时间 
	int finishtime;        //完成时间 
	int waitingtime;       //等待时间 
	int cycletime;        //周转时间 
	double wctime;        //带权周转时间 
};
struct PCB pcb[100];
/*输入函数*/ 
int input(int n)   
{
	printf("请依次输入进程号、到达时间、运行时间:\n");
	for(int i=0;i<n;i++)
	{
		scanf("%s\t%d\t%d",pcb[i].name,&pcb[i].arrivaltime,&pcb[i].runtime);
	}
 } 
 /*输出函数*/ 
int output(int n)  
{
	printf("\n======================================================================================================================\n");
	printf("进程号 \t到达时间\t运行时间\t开始时间\t完成时间\t等待时间\t周转时间\t带权周转时间\n");
	printf("----------------------------------------------------------------------------------------------------------------------\n");
	for(int i=0;i<n;i++)
	{
	printf("%3s\t  %d\t\t   %d\t\t   %d\t\t   %d\t\t   %d\t\t   %d\t\t   %.2lf\n",pcb[i].name,pcb[i].arrivaltime,pcb[i].runtime,pcb[i].starttime,pcb[i].finishtime,pcb[i].waitingtime,pcb[i].cycletime,pcb[i].wctime);
	}
	printf("----------------------------------------------------------------------------------------------------------------------\n");
	printf("\t平均周转时间    \t\t%.2lf\t\n",atime);
	printf("----------------------------------------------------------------------------------------------------------------------\n");
	printf("\t平均带权周转时间\t\t%.2lf\t\n",awtime);
	printf("======================================================================================================================\n"); 
}
/*按到达时间进行排序*/ 
int rank(int n)
{
	struct PCB t;
	for(int j=0;j<n-1;j++)  //冒泡法排序
	for(int i=0;i<n-1-j;i++)
    {
    	if(pcb[i].arrivaltime>pcb[i+1].arrivaltime)
		{
			t=pcb[i];
			pcb[i]=pcb[i+1];
			pcb[i+1]=t;
		} 
	}
}
/*先来先服务算法*/
int FCFS(int n)
{
/*完成时间*/
	if(pcb[0].arrivaltime!=0) //第一个进程到达时间不为0时,其完成时间=开始时间+运行时间
	{
		pcb[0].finishtime=pcb[0].starttime+pcb[0].runtime;
	}
	else
		pcb[0].finishtime=pcb[0].runtime; //第一个进程到达时间为0时,其完成时间=运行时间
		for(int i=1;i<n;i++)
		{
			if(pcb[i-1].finishtime>=pcb[i].arrivaltime) //如果前一个进程的完成时间大于等于当前进程的到达时间
			{
				pcb[i].finishtime=pcb[i-1].finishtime+pcb[i].runtime; //当前进程的完成时间=前一个进程的完成时间+该进程的运行时间
			 } 
			else
			{
				pcb[i].finishtime=pcb[i].arrivaltime+pcb[i].runtime; //否则为当前进程的到达时间+运行时间
			}
		 }
 /*开始时间*/ 
	pcb[0].starttime=pcb[0].arrivaltime; //第一个进程的开始时间即到达时间
	for(int i=1;i<n;i++)
	{
		pcb[i].starttime=pcb[i-1].finishtime; //从第二个进程开始,开始时间=前一个进程的完成时间
	}
/*等待时间 周转时间 带权周转时间*/
 	for(int i=0;i<n;i++) 
 	{
 		pcb[i].waitingtime=pcb[i].starttime-pcb[i].arrivaltime; //等待时间=开始时间-到达时间
pcb[i].cycletime=pcb[i].finishtime-pcb[i].arrivaltime; //周转时间=完成时间-到达时间
pcb[i].wctime=pcb[i].cycletime/(pcb[i].runtime*1.0); //带权周转时间=周转时间/运行时间
	 }
/*平均周转时间 平均带权周转时间*/
int sum1=0;
double sum2=0;
for(int i=0;i<n;i++)
		{
			sum1+=pcb[i].cycletime;    //求所有进程周转时间的和
sum2+=pcb[i].wctime;      //求有所进程周转时间的和
		}
		atime=sum1/(n*1.0);   //平均周转时间=所有进程周转时间的和/进程数
awtime=sum2/n;       //平均带权周转时间=所有进程周转时间的和/进程数 
	}
	/*主函数*/ 
int main()
{
	printf("先来先服务FCFS算法模拟\n请输入进程个数:\n");
    int n;
    scanf("%d",&n);  //输入进程数 n
input(n);       //输入函数
rank(n);        //排序函数,按到达时间给各进程排序 (升序)
    FCFS(n);         //先来先服务算法函数,计算各种时间
    output(n);       //输出函数
    return 0;
}

(6) Test data or screenshot:

 (6) Analysis of running results: According to the first-come-first-served algorithm, first sort them according to their arrival time. According to the input information of the process, the arrival time of the first process a is 0, its completion time = running time = 1, and the rest of the processes The completion time of the process = the completion time of the previous process + the running time of the process, (for example, the completion time of b=1+100=101, the completion time of c=101+1=102, the completion time of d=102+100 =201) ; the start time of the first process a = arrival time = 0, the start time of other processes = the completion time of the previous process, (for example, the start time of b = the completion time of a = 1, the start time of c = the completion time of b = 101, the start time of d = the completion time of c = 102) ; the waiting time of each process = start time - arrival time (for example, the waiting time of a = 0-0 = 0, the waiting time of b Time=1-1=0, waiting time of c=101-2=99, waiting time of d=102-3=99); turnaround time=completion time-arrival time (for example, turnaround time of a=1-0 =1, turnaround time of b=101-1=100, turnaround time of c=102-2=100, turnaround time of d=202-3=199); weighted turnaround time=turnover time/running time (eg, The weighted turnover time of a=1/1=1, the weighted turnover time of b=100/100=1, the weighted turnover time of c=100/1=100, the weighted turnover time of d=199/100= 1.99) ; average turnaround time = sum of all process turnaround times/number of processes (1+100+100+199)/4=100 ; average weighted turnaround time = sum of all process weighted turnaround times/number of processes (1+ 1+100+1.99)/4=26 .

2. Time slice round-robin scheduling algorithm

(1) Algorithm content: The time slice round-robin scheduling algorithm is mainly used for low-level scheduling, and the scheduling method is actually a clock-based preemptive scheduling algorithm. In a system using the time slice round-robin scheduling algorithm, the process/thread ready queues are queued in the order of arrival time. According to the first-come-first-serve principle, all processes that need to be executed are arranged in an ascending sequence according to the arrival time. Each time a process is given a time slice of the same size. In this time slice, if the execution of the process ends, the process is deleted from the process queue. If the process does not end, the process is stopped and then changed to a waiting state, and placed in the The tail of the process queue until all processes have finished executing.

(2) Algorithm requirements: Each process is represented by a process control block (PCB). The process control block can contain the following information: process name, arrival time, running time, completion time, turnaround time, authorized turnaround time, completed process flag, remaining service time, etc. The running time of a process is calculated in units of time slices.

(3) Design idea: Every time when scheduling, always select the leader process of the ready queue, and let it run a time slice preset by the system on the CPU. A process that has not finished running within a time slice returns to the end of the thread queue and re-queues to wait for the next scheduling. Time slice round-robin scheduling belongs to preemptive scheduling and is suitable for time-sharing systems.

(4) Algorithm analysis: first define an RR structure;

input() input function;

The rank() function sorts the process arrival time;

The rr_pcb() function executes the round-robin scheduling algorithm;

output() output function;

main() main function.

(5) Core code:

#include<stdio.h>
   double atime;            //平均周转时间 
   double awtime;    //平均带权周转时间
 struct RR
 {
 	char name[20];         //进程号 
 	int arrivaltime;       //到达时间 
	int runtime;           //运行时间
	int starttime;         //开始时间 
	int finishtime;        //完成时间
	int cycletime;      //周转时间 
	double wctime;      //带权周转时间
	int sign;          //完成进程标志 
	int st1;    //剩余服务时间 
  };
  struct RR rr[100];
  /*输入函数*/ 
int input(int n)
{
	printf("请依次输入进程号、到达时间、运行时间:\n");
	for(int i=0;i<n;i++)
	{
		rr[i].sign=0; 
		scanf("%s\t%d\t%d",rr[i].name,&rr[i].arrivaltime,&rr[i].runtime);
		rr[i].st1=rr[i].runtime;
	} 
}
/*采用冒泡法,按进程的到达时间对进程进行排序*/
int rank(int n)
{
	int i,j;
	struct RR temp; 
	for(j=0;j<n-1;j++)
	for(i=0;i<n-1-j;i++)
	{
		if(rr[i].arrivaltime>rr[i+1].arrivaltime)
		{
			temp=rr[i];
			rr[i]=rr[i+1];
			rr[i+1]=temp;
		}
	}
}
/*执行时间片轮转调度算法*/ 
int rr_pcb(int n)  
{
	printf("请输入时间片:\n");
	int t;
	scanf("%d",&t);  //输入时间片
	int time=rr[0].arrivaltime;     //给当前时间time赋初值
	int flag=1;          //标志就绪队列中有进程
	int sum=0;          //记录完成的进程数
	printf("\n====================================================================================================================\n");
	printf("进程号 \t到达时间\t运行时间\t开始时间\t完成时间\t周转时间\t带权周转时间\n");
	printf("--------------------------------------------------------------------------------------------------------------------\n");
	while(sum<n) //当完成的进程数小于进程总数
	{
	flag=0;    //标记就绪队列没有进程
	for(int i=0;i<n;i++) //时间片轮转法执行各进程 
	{
		if(rr[i].sign==1)//已完成进程 
		continue;
		else//未完成的进程
		{
			if(rr[i].st1<=t && time>=rr[i].arrivaltime)//还需运行的时间小于等于一个时间片 
			{
	 	      flag=1;  //把进程加入到就绪队列中
	       	  time+=rr[i].st1;
	 	      rr[i].sign=1; //此进程完成
	          rr[i].finishtime=time;  //完成时间 
              rr[i].cycletime=rr[i].finishtime-rr[i].arrivaltime;  //计算周转时间=完成时间-到达时间 
			  rr[i].wctime=rr[i].cycletime/(rr[i].runtime*1.0);   //计算带权周转时间=周转时间/服务 
			  printf("%3s\t  %d\t\t   %d\t\t   %d\t\t   %d\t\t   %d\t\t   %.2lf\n",rr[i].name,
	rr[i].arrivaltime,rr[i].runtime,time-rr[i].st1,time,rr[i].cycletime,rr[i].wctime);
			}		 	    
			else if(rr[i].st1>t&&time>=rr[i].arrivaltime)    //还需服务时间至少大于一个时间片 
			{
	 		  flag=1;  //把进程加入到就绪队列中
	 		  time+=t;
			  rr[i].st1-=t;
              rr[i].cycletime=rr[i].finishtime-rr[i].arrivaltime; //计算周转时间=完成时间-到达时间 
			  rr[i].wctime=rr[i].cycletime/(rr[i].runtime*1.0);  //计算带权周转时间=周转时间/服务
			  printf("%3s\t  %d\t\t   %d\t\t   %d\t\t   %d\t\t   %d\t\t   %.2lf\n",rr[i].name,
	rr[i].arrivaltime,rr[i].runtime,time-t,time,rr[i].cycletime,rr[i].wctime);
			} 
	    	if(rr[i].sign==1)
 		       sum++;     //一个进程执行完就+1
		} 
	 } 
	} 
	/*平均周转时间  平均带权周转时间*/ 
	int sum1=0;
	double sum2=0;
	for(int i=0;i<n;i++)
	{
		
		sum1+=rr[i].cycletime;  //求所有进程周转时间的和 
		sum2+=rr[i].wctime;  //求所有进程带权周转时间的和 
	}
	atime=sum1/(n*1.0);  //平均周转时间=有进程周转时间的和/进程数 
	awtime=sum2/n;   //平均带权周转时间=所有进程带权周转时间的和/进程数 
 } 
 /*输出函数*/
 int output(int n)
 {
    printf("--------------------------------------------------------------------------------------------------------------------\n");
	printf("\t平均周转时间    \t\t%.2lf\t\n",atime);
	printf("--------------------------------------------------------------------------------------------------------------------\n");
	printf("\t平均带权周转时间\t\t%.2lf\t\n",awtime);
	printf("====================================================================================================================\n"); 
}
/*主函数*/
int main()
{
	printf("时间片轮转调度算法\n请输入总进程数:\n");
	int n;
	scanf("%d",&n);   //输入总进程数 
	input(n);   //输入函数 
	rank(n);    //排序函数 
	rr_pcb(n);   //计算各时间 
	output(n);   //输出函数 
	return 0;
 }

(6) Test data or screenshots: (See Figure 1 for time slice 1, see Figure 2 for time slice 5)

Figure 1 Screenshot of running results when time slice = 1

Figure 2 Screenshot of running results when time slice = 5

(7) Analysis of running results: the execution time image is as follows,

Figure 4-24 Execution time image

When the time slice = 1, the running time of the four processes a, b, c, and d are all longer than the specified time slice. If they do not finish running within a time slice, they all need to return to the end of the ready queue and wait for the next scheduling to continue execution. . The CPU is assigned to the first process in the current ready queue.

When time slice = 5, the running time of the first process is equal to 20>5, and if the running time is not completed within one time slice, process a returns to the end of the ready queue to requeue and wait for the next scheduling; the running time of the second process is equal to 10>5, when the specified time slice is used up, process b returns to the end of the ready queue, waiting to be scheduled for execution again; the running time of the second process is equal to 15>5, then process c returns to the end of the ready queue, and waits until It will be put into operation when it turns to itself next time; the running time of the fourth process is 5, and it just finishes running within one time slice, then process d gives up the right to use the CPU. At this time, the process scheduler allocates the CPU to the first process in the current ready queue, namely process a.

3. Priority Scheduling Algorithm

(1) Algorithm content: The priority scheduling algorithm can be applied to both high-level scheduling (job scheduling) and low-level scheduling (process scheduling), and it can also be used in real-time systems. In advanced scheduling, the priority number scheduling algorithm selects the job with the highest priority from the backup job queue and loads it into memory, allocates corresponding resources for it, and creates a process and puts it in the process ready queue. In low-level scheduling, the priority scheduling algorithm selects the process with the highest priority from the process ready queue to allocate CPU to it and put it into operation. If there are multiple jobs/processes with the highest priority, it can be combined with first-come, first-served or short-job/short-process priority scheduling strategies.

(2) Algorithm requirements: Each process is represented by a Process Control Block (PCB). The process control block can contain the following information: process name, running time, priority number, process status, etc. The priority number of the process and the required running time can be manually specified in advance (it can also be generated by random numbers). The state of each process can be ready W (Wait), run R (Run) or complete one of the 3 states of F (Finish).

(3) Design idea: Using the preemptive priority scheduling algorithm, the ready process/thread with the highest priority gets the CPU to run first, and is allowed to be preempted by the ready process/thread with higher priority during the running process. If there are multiple processes with the highest priority, a first-come, first-served scheduling policy is combined. Before each run, its "priority number" and "required running time" are arbitrarily determined for each process. The processor always chooses the leader process to run. The method of dynamically changing the priority number is adopted. Every time the process runs, the priority number is reduced by 1, and the required running time is reduced by 1. After the process runs once, if the required running time is not equal to 0, it will be added to the queue, otherwise, the status will be changed to "end" and the queue will be exited. If the ready queue is empty, end, otherwise repeat the above steps.

(4) Algorithm analysis: define the process control block;

input() function;

output() function;

The max_priority() function finds the process with the highest priority in the ready state;

The psa_pcb() function is a priority scheduling algorithm;

main() main function;

(5) Core code:

#include<stdio.h>
/*结构体*/
struct PSA
{
char name[10];      //进程名
int runtime;       //运行时间
int priority;      //优先数
char state;        //状态,三状态:W-就绪;R-运行;F-结束
};
struct PSA psa[10];   //定义进程控制块数组

/*输入函数*/
int input(int n)
{ 
printf("请输入PCB的进程名,运行时间,优先数:\n");
for(int i=0;i<n;i++)    //i为进程编号
{
scanf("%s\t%d\t%d",&psa[i].name,&psa[i].runtime,&psa[i].priority);
psa[i].state=‘W’;    //初始状态都设为就绪
getchar();
}
}
/*输出函数*/
int output(int n)
{ 
printf("\n==============================\n");
printf("进程号 运行时间 优先数 状态\n");
printf("------------------------------\n");
for(int i=0;i<n;i++)
printf("%s %7d%9d\t%s\n",psa[i].name,psa[i].runtime,psa[i].priority,&psa[i].state);
printf("==============================\n");
}
/*进程在就绪状态时找出最大优先数进程(返回值为最大优先数编号)*/
int max_priority(int n)
{
int max=-1;    //max为最大优先数
int m;     //m为最大优先数进程的编号
for(int i=0;i<n;i++)
{      //进程在就绪状态时找出最大优先数
if(psa[i].state==‘R’)    //进程在运行状态
return -1;
else if((max<psa[i].priority)&&(psa[i].state==‘W’)) //进程在就绪状态
{
max=psa[i].priority;
m=i;     //把最大优先数对应的编号赋给m
}
}
//确保最大优先数进程还没结束运行
if(psa[m].state==‘F’) //最大优先数进程已结束运行
return -1;
else //最大优先数进程还没结束运行
return m; //返回值为最大优先数编号
}
/*优先数调度算法*/
int psa_pcb(int n)
{
int max_time=-1,m=0;
int sum=0;    //sum为程序总运行次数
for(int i=0;i<n;i++)
sum+=psa[i].runtime;
printf("\n初始时各进程信息如下:\n");
output(n);
getchar();
for(int j=0;j<sum;j++)
{
//当程序正在运行时
while(max_priority(n)!=-1)    //max_priority ()为找出最大优先数进程函数,返回最大值对应的编号m
{
if(psa[max_priority(n)].priority!=0)
psa[max_priority(n)].state=‘R’;    //由就绪转为运行态
else
{ //当优先级降为0,进程还没运行完时
for(int i=0;i<n;i++)
if(max_time<psa[i].runtime)
{
max_time=psa[i].runtime;
m=i;    //返回对应的编号
}
max_time=-1;
psa[m].state=‘R’;    //状态转为运行态
}
}
    //判断程序状态(对优先数和运行时间操作) 
    for(int i=0;i<n;i++)
    {
        if(psa[i].state==‘R’)   //当进程处于运行状态时 
        {
            if(psa[i].priority>0)     //优先数>0
               psa[i].priority--;  //每运行一次优先数-1
            psa[i].runtime--;   //每运行一次运行时间-1
        }
        if(psa[i].runtime==0)  //运行时间完
			psa[i].state=‘F’;   //进程状态转为完成状态
        else     //运行时间没完
			psa[i].state=‘W’;   //进程状态转为就绪状态
    } 
    output(n);
    getchar();
}    
}
/*主函数*/
int main()
{
	printf("优先数调度算法:\n输入总进程数:\n");
	int n;
	scanf("%d",&n);   //输入总进程数n
    input(n);    //输入函数
    psa_pcb(n);   //优先数调度算法
    return 0;
}

 
(6) Test data or screenshot:

  


 

(7) Analysis of running results: At the beginning, the states of the five processes a, b, c, d, and e are all in the ready state (W), among which c has the highest priority, then c is first to be run by the CPU, and its running time is 2. In the running state, the running time is decremented by 1, and the priority number is decremented by 1; the running time of process a is 0, and the state of a changes from ready state to completed state; after that, the priority numbers of c and e are the largest, but According to the first-come-first-serve scheduling policy, c is in the running state first, the priority number is reduced by 1, and the running time is reduced by 1 to 0, so c becomes the completed state; at this time, only three processes b, d, and e are in the ready state, of which e The priority number of e is the largest, then e gets the CPU and puts it into operation, its running time is reduced by 1, and the priority number is reduced by 1; then the priority numbers of b and e are the same, according to the first-come-first-serve scheduling policy, then b preempts the CPU and is in the running state. If the running time is reduced by 1 to 0, then b becomes completed; at this time, only two processes d and e are left, and e has a higher priority number, then e preempts the CPU and is in the running state, and the priority number and running time are reduced by 1; e The priority number minus 1 is the same as that of d, but according to the first-come-first-served principle, d gets the CPU first and is in the running state, and the priority number and running time are reduced by 1; at this moment, the priority number of e is larger than d, so e gets the CPU Run, the running time and the priority number minus 1; the priority numbers of d and e are the same, but d runs first, the running time and the priority number minus 1, then the priority number of e is greater than d, e gets the CPU, and the running time is reduced by 1. 0, e is in the completed state; in the end, only d is left to get the CPU to run, and the running time is reduced by 1 to 0, becoming the completed state. In short, the process with high priority first obtains the CPU in the running state. After running once, the running time and priority number are reduced by 1. When the running time is not 0, it is added to the ready queue. When the running time is equal to 0, the state is changed to end (F). If there are multiple processes with the same priority, they will be processed on a first-come, first-served basis.

Guess you like

Origin blog.csdn.net/weixin_57130368/article/details/129258889