【操做系統】先來先服務和短做業優先算法(C語言實現)

【操做系統】 先來先服務算法和短做業優先算法實現

介紹:

1.先來先服務 (FCFS: first come first service)

若是早就緒的進程排在就緒隊列的前面,遲就緒的進程排在就緒隊列的後面,那麼先來先服務(FCFS: first come first service)老是把當前處於就緒隊列之首的那個進程調度到運行狀態。也就說,它只考慮進程進入就緒隊列的前後,而不考慮它的下一個CPU週期的長短及其餘因素。FCFS算法簡單易行,是一種非搶佔式策略,但性能卻不大好。算法

簡單來講,先來先服務就是那個進程到達時間最先,那麼CPU就先處理哪一個進程。

2.短做業優先(SJF, Shortest Job First)

對預計執行時間短的做業(進程)優先分派處理機。一般後來的短做業不搶先正在執行的做業。函數

也就是說,不但要考慮進程的到達時間,還要考慮進程須要運行的時間。

當一個進程正在運行時,假若有其餘的進程到達,那麼這些到達的進程就須要按照其須要運行的時間長短排序,運行時間短的在前,運行時間長的在後。

3.例子:

在這裏插入圖片描述

4.運行截圖

1.先來先服務性能

在這裏插入圖片描述
2.短做業優先
在這裏插入圖片描述ui

5.話很少說,直接上代碼。第一次寫,有不少不足的地方。但願你們看到能夠幫忙糾正一下,謝謝你們。

#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)->arrive_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+new_quene.front+i)->arrive_time;
                (new_quene.base+new_quene.front+i)->start_time = (new_quene.base+new_quene.front+i)->arrive_time;
                (new_quene.base+new_quene.front+i)->finish_time = (new_quene.base+new_quene.front+i)->arrive_time + (new_quene.base+new_quene.front+i)->service_time;
            }
            else
            {
                start = (new_quene.base+new_quene.front+i-1)->finish_time;
                (new_quene.base+new_quene.front+i)->finish_time = (new_quene.base+new_quene.front+i)->start_time + (new_quene.base+new_quene.front+i)->service_time;
            }    
            service = (new_quene.base+new_quene.front+i)->service_time;
            arrive = (new_quene.base+new_quene.front+i)->arrive_time;
            finish = start + (new_quene.base+new_quene.front+i)->service_time;

            for(int j = 0;j <= q.length;j ++){       //假如一個進程運行結束前,有新的進程到達,那麼就加入一個臨時隊列。
                 if ((q.base+q.front+j)->arrive_time <= finish && (q.base+q.front+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+q.front+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+q.front+j)->arrive_time == min_arrive_time && (q.base+q.front+j)->status == 0){
                        (q.base+q.front+j)->status = 1;
                        rudui(&new_quene,*(q.base+q.front+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+q.front+j)->service_time == min_service_time && (q.base+q.front+j)->status == 0){
                        (q.base+q.front+j)->status = 1;
                        rudui(&new_quene,*(q.base+q.front+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");
}

但願你們看到不足的地方能夠糾正一下。謝謝你們!
完美撒花!操作系統

相關文章
相關標籤/搜索