最早截止时间优先(earliest deadline first,EDF)算法是根据任务的优先级,任务的截止时间越早,其优先级越高,具有最早截止时间的任务排在队列的前面。调度程序在选择任务时,总是选择就绪队列中的第一个任务,并为之分配处理机。EDF算法即可用于抢占式调度方式中,也可用于非抢占式调度方式中。
1.非抢占式调度方式用于非周期实时任务(参考《计算机操作系统慕课版》)
大家可通过以上图片了解非抢占式,本次主要以抢占式为主。
2.抢占式调度方式用于周期实时任务
我们先从《计算机操作系统慕课版》一个实例出发:现有两个周期实时任务A、B,其周期时间分别为20ms和50ms,每次周期的处理时间分别为10ms和25ms。
首先我们得先思考这个实例是否可行?
思考:任务A、B能否实现实时调度?为什么?
一个小知识点:假定系统中有m个周期性的HRT任务,它们一个周期内的处理时间为Ci,周期时间表示为Pi,则在单处理情况下,必须满足:C1/P1+C2/P2+……+Cm/Pm<=1 即每个任务的处理时间与周期时间比的和不超过1。我是这么理解:Ci/Pi是指i任务时间占用率,如果所有任务占用率小于等于100%,说明有机会按照一定的次序分配,如果超过100%肯定不会实现。
对本上面的实例 CA/PA+CB/PB=1 <=1,满足C1/P1+C2/P2+……+Cm/Pm<=1,所以可以实现。
思考:如果采用EDF算法实现?(参考《计算机操作系统慕课版》p88图3-8,即下图)
第一行是两个任务到达时间、执行时间和最晚截止时间图。
第二、三行是为了说明通常的优先级调度不能适用于实时系统,如果按照固定优先级调度下去(第二行A优先、第三行B优先),你会发现都会失败。
第四行则是采用EDF算法的时间图,根据截止时间决定优先级,截止时间越早,越优先。
那么你可能会问:如果截止时间相同怎么办?
如果截止时间相同先来的先执行,能不换就不换。
思考:EDF算法调度时机是什么?
在我看来:1.当前任务结束;2.新任务到达。(如果有错,欢迎大家批评指正)
思考:如何编写程序实现EDF算法?
代码思路:
首先确定好最后的截止时间我在代码中称之为大周期t,也就是所有任务的周期的最小公倍数;
其次就是利用公式判断可行性,前面已经提到过这个知识点;
最后就是利用结构体+sort+cmp确定调度顺序,然后不断地更新,使用结构体可以记录更多的信息。由于实例中任务数是n,我这里代码第6行n赋值为2,可根据实际需求更改。
欢迎各位大佬批评指正!
#include<cstdio>
#include<cstring>
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
const int n=2;//n表示任务数目,可以按照进程数目来更改n
int id;//该目的是为不重复输出某一个任务
int ztime=0;//当前时间
int t=1;//t表示大周期
//EDF调度时机:1.当前任务结束(判断剩余的)2.新任务到达 /大周期得算出各个任务周期时间的最小公倍数
int gcd(int x,int y)
{ //最大公约数
return y?gcd(y,x%y):x;
}
int lcm(int x, int y)
{ //最小公倍数
return x*y/gcd(x,y);
}
struct Task
{
int id;//序列号
double ctime;//执行时间
double ptime;//周期时间
double atime;//到达时间
double deadline;//截止时间
double stime;//剩余时间
};
Task a[n];
bool cmp2(Task a,Task b)//排序规则
{
if((a.atime<=ztime&&b.atime<=ztime)||(ztime>=a.atime&&ztime>=b.atime)) return a.deadline<b.deadline;//如果两个任务都到了或都没到,按截止时间排序
else if (a.atime<=ztime&&b.atime>ztime)return true;//如果一个任务到了,另一个没到,任务先到的排在前面
else return false;
}
void gx()
{//随着时间不断更新
if(a[0].stime>0)
{
a[0].stime--;
}
if(a[0].stime<=0)
{
a[0].atime+=a[0].ptime;
a[0].deadline+=a[0].ptime;
a[0].stime+=a[0].ctime;
}
// cout<<"gx()第"<<a[0].id<<"的剩余时间"<<a[0].stime<<endl;当时debug使用的
return;
}
int EDFdd()
{
double m=0.0;//ci求和;
cout<<"请分别输入这"<<n<<"个任务的序列号、第一个周期的执行时间id、ci、周期Pi"<<endl;
for(int i=0;i<n;i++)
{
cin>>a[i].id>>a[i].ctime>>a[i].ptime;
a[i].atime=0;//默认到达时间统一为0
a[i].stime=a[i].ctime;//剩余时间参考执行时间
a[i].deadline=a[i].atime+a[i].ptime;//截止时间
m+=a[i].ctime/a[i].ptime;//需要根据公式判断可行吗
t=lcm(t,a[i].ptime);//大周期=各个周期的最小公倍数
}
if(m>1)//利用公式判断是否可实现
{
cout<<"抱歉无法实现"<<endl;
return 0;
}
sort(a,a+n,cmp2);id=a[0].id;//把第一个执行序的赋值给id
for( ;ztime<=t;ztime++)
{
sort(a,a+n,cmp2);
if(a[0].atime<=ztime)//如果有任务到达就可执行
{
if(ztime==0)//输出一个执行的
cout<<"在"<<ztime<<"ms"<<a[0].id<<"开始执行"<<endl;
else
{
if(id!=a[0].id)//为了不重复输出
{
cout<<"在"<<ztime<<"ms"<<a[0].id<<"开始执行"<<endl;
id=a[0].id;
}
}
gx();//更新
}
}
cout<<"在"<<t<<"ms结束一个大周期"<<endl;
return 0;
}
int main()
{
EDFdd();
return 0;
}