【操作系统】先来先服务和短作业优先算法(C语言实现)
【操作系统】 先来先服务算法和短作业优先算法实现
介绍:
1.先来先服务 (FCFS: first come first service)
如果早就绪的进程排在就绪队列的前面,迟就绪的进程排在就绪队列的后面,那么先来先服务(FCFS: first come first service)总是把当前处于就绪队列之首的那个进程调度到运行状态。也就说,它只考虑进程进入就绪队列的先后,而不考虑它的下一个CPU周期的长短及其他因素。FCFS算法简单易行,是一种非抢占式策略,但性能却不大好。
简单来说,先来先服务就是那个进程到达时间最早,那么CPU就先处理哪个进程。
2.短作业优先(SJF, Shortest Job First)
对预计执行时间短的作业(进程)优先分派处理机。通常后来的短作业不抢先正在执行的作业。
也就是说,不但要考虑进程的到达时间,还要考虑进程需要运行的时间。
当一个进程正在运行时,假如有其他的进程到达,那么这些到达的进程就需要按照其需要运行的时间长短排序,运行时间短的在前,运行时间长的在后。
例子:

话不多说,直接上代码。第一次写,有很多不足的地方。希望大家看到可以帮忙纠正一下,谢谢大家。
#include <stdio.h>
#include <stdlib.h>
#define MAX 10
typedef struct PCB {
    int id,arrive_time,service_time,start_time,finish_time;     //进程id、到达时间、服务时间、开始时间、完成时间
    float zhouzhuan_time,daiquanzhouzhuan_time;                 //周转时间、带权周转时间。。。只能说我的拼英。。。emm,。。尴尬。。
    int status;
}PCB;
typedef enum {
	OK,ERROR
}Status;
typedef enum {
	FALSE,TRUE
}Bool;
typedef PCB datatype;
typedef struct LinkQueue {
    int front;
    int rear;
    int length;
    datatype* base;
}quene;
int arrive[MAX];     // 记录每个作业的到达时间
int service[MAX];    //记录每个作业的服务时间
int num;            //输入的进程个数
quene init(){
    quene q_pcb;
    q_pcb.base = (datatype *)malloc(sizeof(datatype)*MAX);
    q_pcb.front = q_pcb.rear = 0;
    q_pcb.length = 0;
    return q_pcb;
}
Bool isFull(quene *q) {
	if ((q->rear + 1) % MAX == q->front) {
		return TRUE;
	}
	return FALSE;
}
Bool isEmpty(quene *q) {
	if (q->rear == q->front) {
		return TRUE;
	}
	return FALSE;
}
Status rudui(quene *q,datatype p){      //入队。。。emmmm。。。尴尬。。。当时脑子抽了。。写成了拼英。  后来写完了。。。用的地方太多了。。就没修改了。。
	if (isFull(q))
	{
		return ERROR;
	}
    *(q->base + q->rear) = p;
    q->rear=(q->rear + 1) % MAX;
    q->length ++;
    return OK;
}
Status chudui(quene *q){                //出队。。。emmmm。。。尴尬。。。当时脑子抽了。。写成了拼英。  后来写完了。。。用的地方太多了。。就没修改了。。
    if (isEmpty(q) == TRUE) {
         return ERROR;
	}
    q->length --;
    q->front = (q->front+1)%MAX;
    return OK;
}
void input(quene *q) /* 建立进程控制块队列 */
{
    printf("请输入进程的个数:\n");
    scanf("%d",&num);
    printf("请输入各进程的服务时间:\n");
    int count = num;
    int count2 = num;
    int i = 0;
    while(i < count2)
    {
        datatype temp;
        temp.id = i;
        temp.status = 0;            //将所有的访问状态都置为0 表示未加入队列
        scanf("%d",&temp.service_time);
        service[i] = temp.service_time;
        rudui(q,temp);
        i ++;
    }
    i = 0;
    printf("length=%4d\n",q->length);
    printf("请输入各进程的到达时间:\n");
    while (i < count)
    {
        scanf("%d",&(q->base+i)->arrive_time);
        arrive[i] = (q->base+i)->arrive_time;
        i ++;
    }
}
void print_pcb(quene *q){           //格式化打印 , 并计算相关的信息
    float ave_zhouzhuan = 0;
    float ave_daiquan = 0;
    for (int i = 0; i < q->length; i++)
    {
        if(i == 0){
            (q->base+i)->start_time = (q->base+i)->start_time;  //第一个的开始时间
        }
        else
        {
            (q->base+i)->start_time = (q->base+i-1)->finish_time;
        }
        (q->base+i)->finish_time = (q->base+i)->start_time + (q->base+i)->service_time;   //结束时间
        (q->base+i)->zhouzhuan_time = (float)((q->base+i)->finish_time - (q->base+i)->arrive_time);  //周转时间
        if((q->base+i)->service_time == 0){
            (q->base+i)->daiquanzhouzhuan_time = (q->base+i)->zhouzhuan_time;
        }
        else
        {
            (q->base+i)->daiquanzhouzhuan_time = (q->base+i)->zhouzhuan_time/(q->base+i)->service_time; //带权周转时间
        }
        ave_zhouzhuan += (q->base+i)->zhouzhuan_time;
        ave_daiquan += (q->base+i)->daiquanzhouzhuan_time;
    }
    printf("进程ID\t到达时间\t服务时间\t开始时间\t结束时间\t周转时间\t带权周转时间\n");
    for (int i = 0; i < q->length; i++)
    {
         printf("%4d\t%8d\t%8d\t%8d\t%8d\t%8f\t%8f\n",(q->base+i)->id,(q->base+i)->arrive_time,(q->base+i)->service_time,(q->base+i)->start_time,(q->base+i)->finish_time,(q->base+i)->zhouzhuan_time,(q->base+i)->daiquanzhouzhuan_time);
    }
    printf("平均周转时间=%f\n",ave_zhouzhuan/q->length);
    printf("平均带权周转时间=%f\n",ave_daiquan/q->length);
}
void sort(int array[]){         //排序。    从大到小的顺序。
    int temp;
    for(int i = 0;i < num -1;i ++){
        for(int j = i + 1;j < num;j ++){
            if(array[i] > array[j]){
                temp = array[i];
                array[i] = array[j];
                array[j] = temp;
            }
        }
    }
}
int select__min_arrive(quene *q){       //从到达的进程队列中挑选出到达时间最早的
    int min = (q->base+q->front)->arrive_time;
    for(int i = 1;i < q->length; i ++){
        if (min > (q->base+q->front+i)->arrive_time && (q->base+q->front+i)->status == 0)
        {
            min = (q->base+q->front+i)->arrive_time;
        }
    }
    return min;
}
int select__min_service(quene *qu){     //从到达的进程队列中挑选出所有进程中最短一个进程的服务时间
    int min = (qu->base+qu->front)->service_time;
    for(int i = 0;i < qu->length; i ++){
        if (min > (qu->base+qu->front+i)->service_time && (qu->base+qu->front+i)->status == 0)
        {
            min = (qu->base+qu->front+i)->service_time;
        }
    }
    return min;
}
int main(){
    quene q = init();
    input(&q);
    int select;
    sort(arrive); //按照到达时间排序
    sort(service); // 按照服务时间长短排序
    printf("\n");
    printf("1.先来先服务\t2.短作业优先\t请输入你的选择:\n");
    scanf("%d",&select);
    quene new_q,new_quene;      //两个队列。第一个表示先来先服务队列。第二个是短作业优先队列。
    switch (select)
    {
    case 1:
        new_q  = init();
        for(int i = 0;i < q.length; i ++){          //先来先服务 : 按照到达时间排序然后依次查找入队列
            for(int j = 0;j < q.length;j ++){
                if((q.base+q.front+j)->arrive_time == arrive[i] && (q.base+q.front+j)->status == 0){
                    rudui(&new_q,*(q.base+j));
                    (q.base+j)->status = 1;
                }
            }
        }
        print_pcb(&new_q);
        break;
    case 2:
        int flag = 0;
        new_quene = init();
        quene min_arrive = init();          //用来存放当一个进程正在运行时,新到达的队列
        int count = 0;
        for(int i = 0;i < q.length; i ++){        //先让第一个到达的入队列
            for(int j = 0;j < q.length;j ++){
                if(i == 0 && flag == 0){         //保证第一个到达作业装入系统
                    if((q.base+j)->arrive_time == arrive[0] && (q.base+j)->status == 0){
                         rudui(&new_quene,*(q.base+j));
                         (q.base+j)->status = 1;        //防止重复访问
                         break;
                    }
                }
                else{        //后面的按照服务时间长短入队列
                    // if((q.base+j)->service_time == service[i] && (q.base+j)->status == 0){
                    //     // sjf[index] = (q.base+j)->id;
                    //     // index ++;
                    //      rudui(&new_quene,*(q.base+j));
                    //      (q.base+j)->status = 1;
                    //  }
                }
            }
            break;
        }
        int service,arrive,start,finish;    //用于存放正在运行的进程的服务时间、到达时间、开始时间、完成时间。
        for(int i = 0; i < q.length;i ++){      //按照sjf算法确定后续入队的顺序
            if (i == 0)
            {
                start = (new_quene.base+i)->arrive_time;
                (new_quene.base+i)->start_time = (new_quene.base+i)->arrive_time;
                (new_quene.base+i)->finish_time = (new_quene.base+i)->arrive_time + (new_quene.base+i)->service_time;
            }
            else
            {
                start = (new_quene.base+i-1)->finish_time;
                (new_quene.base+i)->finish_time = (new_quene.base+i)->start_time + (new_quene.base+i)->service_time;
            }
            service = (new_quene.base+i)->service_time;
            arrive = (new_quene.base+i)->arrive_time;
            finish = start + (new_quene.base+i)->service_time;
            for(int j = 0;j < q.length;j ++){       //假如一个进程运行结束前,有新的进程到达,那么就加入一个临时队列。
                 if ((q.base+j)->arrive_time <= finish && (q.base+j)->status == 0)
                 {
                    // printf("进程ID\t到达时间\t服务时间\n");      //调试的时候用的
                    //  printf("%8d\t%8d\t%8d\n",(q.base+j)->id,(q.base+j)->arrive_time,(q.base+j)->service_time);
                     rudui(&min_arrive,*(q.base+j));
                     count ++;
                     flag = 1;
                 }
             }
             if(flag == 0){             //在一个进程执行时,如果没有其他的进程到达,那就直接挑选出最早到达的加入到sjf作业调度队列
                 int min_arrive_time = select__min_arrive(&q);
                 for (int  j = 0; j < q.length; j++)
                {
                    if((q.base+j)->arrive_time == min_arrive_time && (q.base+j)->status == 0){
                        (q.base+j)->status = 1;
                        rudui(&new_quene,*(q.base+j));
                        break;
                    }
                }
             }
             if (flag == 1)              //在一个进程执行时,如果有其他的进程到达,那么就要从已经到达的队列中挑选出服务时间最短的加入sjf队列
             {
                //  printf("进入待队列的进程ID\t到达时间\t服务时间\n");         //主要时调试的时候用的
                //  for (int j = 0; j < min_arrive.length; j++)
                //  {
                //     printf("%8d\t%8d\t%8d\n",(min_arrive.base+min_arrive.front+j)->id,(min_arrive.base+min_arrive.front+j)->arrive_time,(min_arrive.base+min_arrive.front+j)->service_time);
                //  }
                int min_service_time = select__min_service(&min_arrive);
                for (int  j = 0; j < q.length; j++)
                {
                    // printf("%d\t | \t", (q.base+j)->status);
                    if((q.base+j)->service_time == min_service_time && (q.base+j)->status == 0){
                        (q.base+j)->status = 1;
                        rudui(&new_quene,*(q.base+j));
                        flag = 0;
                        break;
                    }
                }
             } 
            for (int j = 0; j < count; j++)     //因为每一个作业运行时,都可能会有新到达的进程,所以需要先把上一个进程运行时到达的进程队列给清空
            {
                chudui(&min_arrive);
            }
            count = 0;
        }
        for(int i = 0;i < new_quene.length; i ++){      //因为计算周转时间等的都放在print_PCB函数中了,所以为了后面直接用那个函数所以就又初始化了一遍
            (new_quene.base + i)->start_time = 0;
            (new_quene.base + i)->finish_time = 0;
        }
        print_pcb(&new_quene);              //格式化打印并计算开始时间。完成时间,等的一些数据
        break;
    }
    system("pause");
}
希望大家看到不足的地方可以纠正一下。谢谢大家!
完美撒花!
【操作系统】先来先服务和短作业优先算法(C语言实现)的更多相关文章
- C语言模拟实现先来先服务(FCFS)和短作业优先(SJF)调度算法
		说明 该并非实现真正的处理机调度,只是通过算法模拟这两种调度算法的过程. 运行过程如下: 输入进程个数 输入各个进程的到达事件 输入各个进程的要求服务事件 选择一种调度算法 程序给出调度结果:各进程的 ... 
- 短作业优先调度算法(SJF)
		假设有n项作业位于就绪队列中,这些作业的提交时间用数组requestTimes按照提交时间的先后顺序存储,对应的作业服务时间(持续时间)用数组durations存储.采用SJF算法,计算n项作业的平均 ... 
- 最短作业优先(SJF)
		1. 最短作业优先: 最短作业优先(SJF)是一种调度任务请求的调度策略.每个任务请求包含有请求时间(即向系统提交的请求的时间)和持续时间(即完成任务所需时间). 当前任务完成后,SJF策略会选择最短 ... 
- 最短寻道优先算法(SSTF)——磁盘调度管理
		原创 最近操作系统实习,敲了实现最短寻道优先(SSTF)——磁盘调度管理的代码. 题目阐述如下: 设计五:磁盘调度管理 设计目的: 加深对请求磁盘调度管理实现原理的理解,掌握磁盘调度算法. 设计内容: ... 
- 用PHP实现URL转换短网址的算法示例
		短网址就是把一个长的地址转换在超级短的网址,然后访问短网址即可跳转到长网址了,下面来看用PHP实现URL转换短网址的算法与例子. 短网址(Short URL) ,顾名思义就是在形式上比较短的网址.在W ... 
- PHP 短连接生成算法
		短连接生成类: <?php #短连接生成算法 class Short_Url { #字符表 public static $charset = "0123456789ABCDEFGHIJ ... 
- php短网址生成算法
		<?php //短网址生成算法 class ShortUrl { //字符表 public static $charset = "0123456789ABCDEFGHIJKLMNOPQ ... 
- 如何做系列(4)-微博URL短网址生成算法原理(java版、php版实现实例)
		短网址(Short URL),顾名思义就是在形式上比较短的网址.通常用的是asp或者php转向,在Web 2.0的今天,不得不说,这是一个潮流.目前已经有许多类似服务,借助短网址您可以用简短的网址替代 ... 
- 数据结构算法C语言实现(八)--- 3.2栈的应用举例:迷宫求解与表达式求值
		一.简介 迷宫求解:类似图的DFS.具体的算法思路可以参考书上的50.51页,不过书上只说了粗略的算法,实现起来还是有很多细节需要注意.大多数只是给了个抽象的名字,甚至参数类型,返回值也没说的很清楚, ... 
随机推荐
- C. Vladik and Memorable Trip 解析(思維、DP)
			Codeforce 811 C. Vladik and Memorable Trip 解析(思維.DP) 今天我們來看看CF811C 題目連結 題目 給你一個數列,一個區段的數列的值是區段內所有相異數 ... 
- Java之HttpClient调用WebService接口发送短信源码实战
			摘要 Java之HttpClient调用WebService接口发送短信源码实战 一:接口文档 二:WSDL 三:HttpClient方法 HttpClient方法一 HttpClient方法二 Ht ... 
- Docker学习笔记之--.Net Core项目容器连接mssql容器(环境:centos7)
			前一节演示在docker中安装mssql,地址:Docker学习笔记之--安装mssql(Sql Server)并使用Navicat连接测试(环境:centos7) 本节演示 .Net Core项目容 ... 
- Docker学习笔记之--.Net Core应用容器通过网桥连接Redis容器(环境:centos7)
			上节演示通过应用容器连接sql server容器,连接:Docker学习笔记之--.Net Core项目容器连接mssql容器(环境:centos7) 本节演示安装 redis容器,通过网桥连接 先决 ... 
- php 使用 phpword 操作 word 读取 word
			思路 1. 加载word文件.2. 循环判断加载出来的数据.( 数据下面有很多个节点 )( 节点是按照数据的类型分类的 例如 无样式的文本是RunText,换行是TextBreak,表格是table. ... 
- python风格代码荟萃
			今天总结一下在python中常用的一些风格代码,这些可能大家都会用,但有时可能也会忘记,在这里总结,工大家参考~~~ 先点赞在看,养成习惯~~~ 标题遍历一个范围内的数字 for i in xrang ... 
- 最全总结 | 聊聊 Python 办公自动化之 Excel(下)
			1. 前言 前面谈到 Python 处理 Excel 文件最常见的两种方式,即:xlrd/xlwt.openpyxl 其中, xlrd/xlwt 这一组合,xlrd 可以负责读取数据,而 xlwt ... 
- 快速了解阿里微服务热门开源分布式事务框架——Seata
			一.Seata 概述 Seata 是 Simple Extensible Autonomous Transaction Architecture 的简写,由 feascar 改名而来. Seata 是 ... 
- W3C中不同标准的含义
			学习CSS/HTML的过程中,当出现释义冲突时,W3C(万维网联盟)官网所陈列的技术标准是最核心的判断参考.但是新手在查阅W3C标准索引页面时,会发现同一个属性或者模型会出现多个不同的阶段规范展示结果 ... 
- linux netfilter rule  match  target 数据结构
			对于netfilter 可以参考 https://netfilter.org/documentation/HOWTO/netfilter-hacking-HOWTO-3.html netfilter ... 
