短进程优先的调度算法详解

一、SPF算法简介

SJF算法

  • SJF(shortest job first)是以进程的运行时间长度作为优先级,进程运行时间越短,优先级越高。

SJF算法的缺点

  • 必须预知进程的运行时间。即使是程序员也很难准确估计进程运行时间。如果估计过低,系统就可能按估计的时间终止进程的运行,但此时进程并未完成,故一般都会偏长估计
  • 对长进程不利。长进程的周转时间会明显地增长。可怕的是,SJF算法完全忽视进程等待时间,可能使进程等待时间过长,出现饥饿现象。
  • 人机无法实现交互。
  • 完全未考虑进程的紧迫程度。不能保证紧迫性进程得到及时处理。

  

                         

二、算法流程图

我做的流程图:http://www.processon.com/diagraming/5835692de4b086d1e79f81af

三、源代码

1. 变量声明与结构体定义

 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4  5 /* run this program using the console pauser or add your own getch, system("pause") or input loop */ 6  7  8 struct pcb{ 9     char name[10];    //进程名 10     int arrival_time; //进程到达时间() 11     int start_time;   //进程开始时间 12     int need_time;      //进程运行所需时间 13     int finish_time;  //运行结束时间 14     struct pcb * link;   //链接下一个pcb的指针 15 };16 17 18 int num = 0;     //输入的进程数 19 typedef struct pcb PCB;    //定义结构体变量 20 /*21 结构体指针p指向 每新建的一个进程22 ready指针指向链表的第一个pcb 
23 finish指针指向完成队列的第一个pcb结构体 
24 */25 struct pcb *p = NULL, *ready = NULL, *finish = NULL;

2. 输入函数

 1 //用来测试链表建立,输入链表结构体数据  2 void print_test(){ 3     int i; 4     struct pcb * test = ready; 5     for(i=0;i<num;i++){ 6         printf("\n进程号:%d,进程名:%s,进程到达时间:%d,进程完成时间:%d", 7                 i,test->name,test->arrival_time,test->need_time); 8         if(NULL != test->link){ 9             test = test->link;10         }11         else{12             printf("\ntest_link end\n");13         }14         15     }16 }17 18 19 20 //输入函数,建立链表 21 void input(){22     int i;23     struct pcb * q;   //定义结构体变量 24     printf("请输入进程数:");25     scanf("%d", &num);26     for(i=0; i<num; i++){27         printf("\n进程号 NO.%d:", i);28         p = (struct pcb*)malloc(sizeof(struct pcb));29         printf("\n输入进程名:");30         scanf("%s", p->name);31         printf("\n请输入进程到达时间:");32         scanf("%d", &p->arrival_time);33         printf("\n请输入进程运行时间:");34         scanf("%d", &p->need_time);35         36         p->link = NULL;37         //建立链表38         if(NULL == ready){   //建立第一个结构体,使指针p,q指向它 39             ready = p;40             q = ready;41         } 
42         else{      //链表建立 43             q->link = p;44             q = p;    
45         }46         printf("input success");47     }48     print_test();   //测试链表是否建立 49 }

3.  所有进程结束后,输出所有进程信息

1 //输出当前运行进程相关数据或者打印暂无进程运行 2 void output(struct pcb * p, int now_time){3     if(NULL == p){4         printf("当前时刻:%d, 暂无进程在运行!\n", now_time);5     }6     else{7         printf("进程名:%s,到达时间:%d,运行需要时间:%d\n",p->name,p->arrival_time,p->need_time);8     }9 }

4.  找出运行时间最短的进程

 1 //sjf  shortest job first最短作业优先  2 struct pcb * SJF(int now_time, int * after){ 3     int min_time = 0;   //最短时间,即优先运行的进程的时间  4     struct pcb * now_progress = NULL, *p = ready; 5     //遍历链表,查找出运行时间最短的进程  6     if (NULL != ready){ 7         while(NULL != p){ 8             if(now_time >= p->arrival_time){   //若进程已经到达,注意:时间单位为1  9                 /*10                 min_time = p->need_time;      //是错误的 
11                 now_progress = p;12                 if(p->need_time < min_time){13                     min_time = p->need_time;14                     now_progress = p;15                 } */16                 if(0 == min_time){  //给最短时间赋初值17                     now_progress = p;18                     min_time = p->need_time;                    
19                 }20                 else{21                     if(p->need_time < min_time){22                         now_progress = p;23                         min_time = p->need_time;24                     }25                 }26             }27             p = p->link;28         }29     }30     *after = min_time + now_time;31     printf("\nSJF:a shortest progress running!\n");32     return now_progress;   //返回指向正在运行进程的指针 33 }

4. 进程执行完毕

 1 //将已经运行完成的进程添加到finish队列,并且进程数减一  2 void destory(struct pcb * p, int now_time){ 3     printf("destory start!\n"); 
 4     struct pcb * q = ready; 5     struct pcb * f = NULL;   //用于finish链表的添加  6  7      8     if(strcmp(p->name, ready->name) == 0){  //若第一个进程完成  9         ready = ready->link;10     }11     //若中间或最后一个进程完成 12     else{13         q = ready;14         while((strcmp(q->link->name,p->name) != 0) && NULL != q->link){15             q = q->link;16         }17         q->link = p->link;18     }19     20      p->finish_time = now_time;    //结束时间21      p->start_time =  now_time - p->need_time;  //开始时间 
22      23     //将已经运行的进程添加到finish队列24     if(NULL == finish){25         finish = p;    //finish指向完成链表的表头 26         p->link = NULL;27     }28     else{29         f = finish;30         while(NULL != f->link){31             f = f->link;32         }33         f->link = p;34         p->link = NULL;35     }36     37     num--;   //进程数减一 38     printf("\ndestory success!\n");39 }

5. 主函数

 1 int main(int argc, char *argv[]) { 2      3      4     input();  //调用输入函数  5      6     int now_time = 0;    //初始时间为0  7     int after = 0;        //执行完一个进程后的时间:优先运行进程的运行时间+当前时间  8     struct pcb * now_progress = NULL;    //now_progress指向正在运行的进程(结构体)  9     struct pcb *m = NULL;10     11     while(num > 0){    //进程数大于0,每次循环num会减一 12         printf("start SJF");13         now_progress = SJF(now_time, &after);  //调用SJF函数,遍历链表 14 15         16         if(NULL != now_progress){17             /*进程执行,每循环一次,当前时间加一18               同时要判断当前时间是否有进程刚好到达正在在等待 */19             for(;now_time < after; now_time++){20                 printf("\n当前时刻:%d", now_time);21                 printf("\n-----------当前执行进程------------\n");22                 output(now_progress, now_time);     //调用output函数 23                 printf("\n-----------等待执行进程------------\n");24                 25                 m = ready;26                 while(NULL != m){   //循环,若当前时间有进程到达,打印相关信息 27                     if(m != now_progress){28                         if(m->arrival_time <= now_time){29                             output(m, now_time);30                             printf("\na new progress arrival\n");31                         }32                     }33                     m = m->link;34                 }35             }36             //进程执行完后调用destory函数 37             destory(now_progress, now_time);38 39         }40         else{   //没有进程在运行 41             output(now_progress, now_time);42             now_time++;43         }44         45     }46     output_all();47     return 0;48     49 }

我写得这么清楚,加上我画的流程图,相信你可以懂的~~

四、测试

五、坑

原本这个函数我是这样写的,但发现运行结果不对~

 按上面代码的运行结果:

按理说,a进程执行后不应该是e进程执行,应该是运行时间最短的d进程执行。同理之后是b, e, c;

我又回去看前面的代码,改正如下:

运行结果:

六、总结知识点

  1. p = (struct pcb*)malloc(sizeof(struct pcb))与p = (struct pcb*)malloc(sizeof(PCB))相同, PCB是结构体struct pcb的一个结构体变量。
  2. 在使用字符串处理函数(puts,gets,strcat,strcpy,strcmp,strlen,strlwr)时,应当在程序文件的开头用#include<string.h>,把"string.h"文件包含到本文件中。
  3. malloc函数。比如:malloc(100) 开辟100字节的临时分配域,函数值为其第1个字节的地址。只提供一个地址。若函数不能成功执行(比如内存不足),则返回空指针。(int*)malloc(sizeof(int)) 将申请得到的空间地址转换成了int类型空间地址最后就可以赋值给指向int型空间的p指针了。
时间: 2024-10-12 15:09:14

短进程优先的调度算法详解的相关文章

操作系统——进程调度之短进程优先

 1.什么是进程调度 无论是在批处理系统还是分时系统中,用户进程数一般都多于处理机数.这将导致它们互相争夺处理机.另外,系统进程也同样需要使用处理机.这就要求进程调度程序按一定的策略,动态地把处理机分配给处于就绪队列中的某一个进程,以使之执行. 2.处理机调度分类 高级.中级和低级调度作业从提交开始直到完成,往往要经历下述三级调度: 高级调度:(High-Level Scheduling)又称为作业调度,它决定把后备进程调入内存运行: 低级调度:(Low-Level Scheduling)又称为

Linux守护进程简介和实例详解

简介 守护进程(Daemon)是运行在后台的一种特殊进程.它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.守护进程是一种很有用的进程.Linux的大多数服务器就是用守护进程实现的.比如,Internet服务器inetd,Web服务器httpd等.同时,守护进程完成许多系统任务.比如,作业规划进程crond,打印进程lpd等. 下面是linux系统中常见的一些守护进程. amd:自动安装NFS(网络文件系统)守侯进程apmd:高级电源管理 Arpwatch:记录日志并构建一个在L

Linux网络编程——进程池实现过程详解(1)

目录 进程池 父进程的实现流程 子进程的实现流程 进程池 父进程的实现流程 1.定义数据结构pChild,申请子进程数目的结构体空间 2.通过循环,socketpair创建全双工管道,创建子进程,将子进程pid,管道对端,是否忙碌等信息存储 3.socket,bind,listen,对应的端口处于监听状态 netstat 4.epoll_create创建epfd,监控socketFd和所有子进程的管道对端 5.while(1)循环 epoll_wait等待客户端的请求及子进程是否有通知 如果so

Linux进程上下文切换过程context_switch详解--Linux进程的管理与调度(二十一)【转】

转自:http://blog.csdn.net/gatieme/article/details/51872659 版权声明:本文为博主原创文章 && 转载请著名出处 @ http://blog.csdn.net/gatieme 目录(?)[-] 前景回顾 1 Linux的调度器组成 2 调度工作 进程上下文 1 进程上下文的概念 2 上下文切换 context_switch进程上下文切换 1 context_switch完全注释 2 prepare_arch_switch切换前的准备工作

haproxy调度算法详解一

HAProxy调度算法 HAProxy通过固定参数balance指明对后端服务器的调度算法,该参数可以配置在listen或backend选项中.HAProxy的调度算法分为静态和动态调度算法,但是有些算法可以根据参数在静态和动态算法中相互转换. haproxy基于socat动态调整权重 socat是linux下的一个多功能网络工具,socat的主要特点是在两个数据流之间建立通道,且支持众多协议和链接方式.如IP.TCP.UDP.IPV6.socket文件等. 使用echo把命令打印出来,通过管道

LVS三种模式及常见的四种调度算法详解

LVS三种工作模式: 1. Virtual server via NAT(VS-NAT) 优点:集群中的物理服务器可以使用任何支持TCP/IP操作系统,物理服务器可以分配Internet的保留私有地址,只有负载均衡器需要一个合法的IP地址. 缺点:扩展性有限.当服务器节点(普通PC服务器)数据增长到20个或更多时,负载均衡器将成为整个系统的瓶颈,因为所有的请求包和应答包都需要经过负载均衡器再生.假使TCP包的平均长度是536字节的话,平均包再生延迟时间大约为60us(在Pentium处理器上计算

广度/宽度优先搜索(BFS)详解

广度/宽度优先搜索(BFS) [算法入门] 1.前言 广度优先搜索(也称宽度优先搜索,缩写BFS,以下采用广度来描述)是连通图的一种遍历策略.因为它的思想是从一个顶点V0开始,辐射状地优先遍历其周围较广的区域,故得名. 一般可以用它做什么呢?一个 广度/宽度优先搜索(BFS) 算法导论里边会给出不少严格的证明,我想尽量写得通俗一点,因此采用一些直观的讲法来伪装成证明,关键的point能够帮你get到就好. 2.图的概念 刚刚说的广度优先搜索是连通图的一种遍历策略,那就有必要将图先简单解释一下.

深入C语言内存区域分配(进程的各个段)详解(转)

原文地址:http://www.jb51.net/article/39696.htm 一般情况下,一个可执行二进制程序(更确切的说,在Linux操作系统下为一个进程单元,在UC/OSII中被称为任务)在存储(没有调入到内存运行)时拥有3个部分,分别是代码段(text).数据段(data)和BSS段.这3个部分一起组成了该可执行程序的文件 (1)代码段(text segment):存放CPU执行的机器指令.通常代码段是可共享的,这使得需要频繁被执行的程序只需要在内存中拥有一份拷贝即可.代码段也通常

Linux进程管理相关命令详解

一.top top命令用于显示系统当前的进程和其他状况:top是一个动态显示过程,即可以通过用户按键来不断刷新当前状态.如果再前台执行该命令,它将独占前台,直到用户终止该程序为止. 其中1-5行为统计信息区,剩余行为进程信息区:1.统计信息区1)第1行为任务队列信息(与uptime命令运行结果相同)字段含义:当前时间     系统启动持续时间   当前登陆用户数    系统负载,即任务队列的平均长度备注:格式为"日期,时:分"  三个数值分别为1,5和15分钟前到现在的均值2)第2行为