處理機排程——實時排程演算法EDF和RMS…
實驗二 處理機排程——實時排程演算法EDF和RMS
一、實驗目的
深入理解處理機排程演算法,瞭解硬實時概念,掌握週期性實時任務排程演算法EDF(Earliest Deadline First)和RMS(Rate Monotonic Scheduling)的可排程條件,並能在可排程情況下給出具體排程結果
二、實驗原理
EDF為可搶先式排程演算法,其排程條件為sum(Ci/Ti)£1;
RMS演算法為不可搶先排程演算法,其排程條件為sum(Ci/Ti)£n(exp(ln(2)/n)-1)。
三、實驗內容
在Linux環境中採用使用者級執行緒模擬實現EDF和RMS兩種實時排程演算法。給定一組實時任務,按照
三、實驗設計
1、實時任務用task資料結構描述,設計四個函式:select_proc()用於實現排程演算法,被選中任務執行proc(),在沒有可執行任務時執行idle(),主函式mian()初始化相關資料,建立實時任務並對任務進行排程。
2、為模擬排程演算法,給每個執行緒設定一個等待鎖,暫不執行的任務等待在相應的鎖變數上。主執行緒按排程演算法喚醒一個子執行緒,被選中執行緒執行一個時間單位,然後將控制權交給主執行緒判斷是否需要重新排程。
四、實驗程式碼
#include"math.h"
#include"sched.h"
#include"pthread.h"
#include"stdio.h"
#include"stdlib.h"
#include"semaphore.h"
typedef struct{ //實時任務描述
char task_id;
int call_num; //任務發生次數
int ci; //任務處理時間
int ti;
//任務發生週期
int ci_left;
int ti_left; //record the reduction of ti \ci
int flag; //任務是否活躍,0否,2是
int arg; //引數
pthread_t th; //任務對應執行緒
}task;
void proc(int *args);
void *idle();
int select_proc(int alg);
int task_num=0;
int idle_num=0;
int alg; //所選演算法,1 for EDF,2 for RMS
int curr_proc=-1;
int demo_time=100; //演示時間
task *tasks;
pthread_mutex_t proc_wait[10]; //the biggest number of tasks
pthread_mutex_t main_wait,idle_wait;
float sum=0;
pthread_t idle_proc;
int main(int argc,char **argv)
{
pthread_mutex_init(& main_wait , NULL);
pthread_mutex_lock(& main_wait); //下次執行lock等待
pthread_mutex_init(& idle_wait , NULL);
pthread_mutex_lock(& idle_wait); //下次執行lock等待
printf("Please input number of real time task:\n");
int c;
scanf("%d",& task_num); //任務數
tasks=(task *)malloc(task_num *sizeof(task));
while((c=getchar())!='\n' && c!=EOF); //清屏
int i;
for(i=0 ; i<task_num ; i++)
{
pthread_mutex_init( & proc_wait[i] , NULL);
pthread_mutex_lock( & proc_wait[i]);
}
for(i=0;i<task_num;i++)
{
printf("Pleased input task id,followed by Ci and Ti:\n");
scanf("%c,%d,%d,",&tasks[i].task_id, &tasks[i].ci, &tasks[i].ti);
tasks[i].ci_left=tasks[i].ci;
tasks[i].ti_left=tasks[i].ti;
tasks[i].flag=2;
tasks[i].arg=i;
tasks[i].call_num=1;
sum=sum+(float)tasks[i].ci / (float)tasks[i].ti;
while((c=getchar())!='\n'&&c!=EOF); //清屏
}
printf("Please input algorithm,1 for EDF,2 for RMS:");
scanf("%d",&alg);
printf("Please input demo time:");
scanf("%d", & demo_time);
double r = 1; //EDF演算法,最早截止期優先排程
if(alg == 2)
{ //RMS演算法,速率單調排程
r=((double)task_num)*(exp(log(2)/(double)task_num)-1);
printf("r is %lf\n",r);
}
if(sum>r) // 綜合EDF和RMS演算法任務不可可排程的情況
{ //不可排程
printf("(sum=%lf>r=%lf),not schedulable!\n",sum,r);
exit(2);
}
//建立閒逛執行緒
pthread_create(& idle_proc , NULL , (void*)idle , NULL);
for(i=0 ;i<task_num ;i++) //建立實時任務執行緒
pthread_create(&tasks[i].th, NULL, (void*)proc, &tasks[i].arg);
for(i=0;i<demo_time;i++)
{
int j;
if((curr_proc=select_proc(alg))!=-1)
{ //按排程演算法選擇執行緒
pthread_mutex_unlock(&proc_wait[curr_proc]); //喚醒
pthread_mutex_lock(&main_wait); //主執行緒等待
}
else
{ //無可執行任務,選擇閒逛執行緒
pthread_mutex_unlock(&idle_wait);
pthread_mutex_lock(&main_wait);
}
for(j=0;j<task_num;j++)
{ //Ti--,直至為0時開始下一週期
if(--tasks[j].ti_left==0)
{
tasks[j].ti_left=tasks[j].ti;
tasks[j].ci_left=tasks[j].ci;
pthread_create(&tasks[j].th,NULL,(void*)proc,&tasks[j].arg);
tasks[j].flag=2;
}
}
}
printf("\n");
sleep(10);
};
void proc(int *args)
{
while(tasks[*args].ci_left>0)
{
pthread_mutex_lock(&proc_wait[*args]); //等待被排程
if(idle_num!=0)
{
printf("idle(%d)",idle_num);
idle_num=0;
}
printf("%c%d",tasks[*args].task_id,tasks[*args].call_num);
tasks[*args].ci_left--; //執行一個時間單位
if(tasks[*args].ci_left==0)
{
printf("(%d)",tasks[*args].ci);
tasks[*args].flag=0;
tasks[*args].call_num++; //
}
pthread_mutex_unlock(&main_wait); //喚醒主執行緒
}
};
void *idle()
{
while(1)
{
pthread_mutex_lock(&idle_wait); //等待被排程
printf("->"); //空耗一個時間單位
idle_num++;
pthread_mutex_unlock(&main_wait); //喚醒主執行緒
}
};
int select_proc(int alg)
{
int j;
int temp1,temp2;
temp1=10000;
temp2=-1;
if((alg==2)&&(curr_proc!=-1)&&(tasks[curr_proc].flag!=0))
return curr_proc;
for(j=0;j<task_num;j++)
{
if(tasks[j].flag==2)
{
switch(alg)
{
case 1: //EDF演算法
if(temp1>tasks[j].ci_left)
{
temp1=tasks[j].ci_left;
temp2=j;
}
case 2: //RMS演算法
if(temp1>tasks[j].ti)
{
temp1=tasks[j].ti;
temp2=j;
}
}
}
}
return temp2; //return the selected thread or task number
};
五、實驗結果