1. 程式人生 > >頁面置換演算法 FIFO和LRU 及各自的命中率

頁面置換演算法 FIFO和LRU 及各自的命中率

(1) 先進先出演算法FIFO:該演算法的實質是選擇作業中在主存駐留時間最長的一頁淘汰,這種演算法容易實現,例如分配一個作業的儲存塊數為m,則只需建立一張m個元素的隊列表Q(0)、Q(1)、…、Q(m-1)和一個替換指標。這個佇列是按頁調入主存的一頁。如圖4-1所示,某時刻調入主存四個塊,(即m=4),它們按頁進入主存的先後順序為4、5、1、2,當需要置換時,總是淘汰替換指標所指向的那一頁, 新調進的頁面裝入主存後,修改相應的佇列元素,然後將替換指標往前移動,使其指向當前最老的一頁。

(2) 最近最少使用頁面淘汰演算法(LRU):這是一種經常使用的方法,有多種不同的實施方案。這裡採用不斷調整頁錶鏈的方法,即總是淘汰頁錶鏈鏈首的頁面,而把新訪問的頁面插入鏈尾。如果當前呼叫頁面已在頁表內,則把它再次調整到鏈尾。這樣就能保證最近使用的頁面總處於靠近鏈尾部分,而不常使用的頁面被移到鏈首,逐個被淘汰。

#include<stdio.h>
#define N 100
#define M 12//作業數
#define ASSIGN 4//儲存塊數
//請求式分頁儲存演算法
//佇列
typedef struct Queue{
  int Q[N];//儲存頁面
  int front,rear;//隊頭和隊尾
}Queue;
//連結串列
typedef struct AdjList{
  int data;
  struct AdjList *next;
}AdjList;
//初始化佇列
void InitQueue(Queue *Q){
   Q->front=-1;
   Q->rear=0;
}
//加入佇列
void EnterQueue(Queue *Q,int n){
  if(Q->front>=Q->rear){
    printf("插入失敗\n");
  }else{
    Q->front++;
    Q->Q[Q->front]=n;
    Q->rear++;
  }
}
//出隊
void OutQueue(Queue *Q){
  if(Q->front<0){
    printf("queue is empty\n");
  }else{
    Q->front--;
    Q->rear--;
  }
}
//在佇列中查詢
int CheckQueue(Queue *Q,int n){
  int i;
  if(Q->front<0){
     //printf("queue is empty\n");
  }else{
     for(i=0;i<Q->rear;i++){
        if(n==Q->Q[i]){
            return 1;
        }
     }
  }
  return 0;
}
//列印佇列
void PrintQueue(Queue *Q){
  int i;
  if(Q->front<0){
     //printf("queue is empty\n");
  }else{
     printf("列印佇列:");
     for(i=0;i<Q->rear;i++){
        printf("%d ",Q->Q[i]);
     }
     printf("\n");
  }
}
//先進先出並算命中率
void FIFO(int A[]){
   int i,num=0,k=0;
   Queue *Q=(Queue *)malloc(sizeof(Queue));
   InitQueue(Q);
   for(i=0;i<M;i++){
     if(CheckQueue(Q,A[i])==1){
        num++;
     }else{
        if(k<ASSIGN){
          EnterQueue(Q,A[i]);
        }else{
          OutQueue(Q);
          EnterQueue(Q,A[i]);
        }
        k++;
     }
     PrintQueue(Q);
   }
   printf("FIFO的命中率為%f\n",(float)num/M);
}
//插入連結串列 頭插法,鏈尾為隊首(邏輯上)
void AddTail(AdjList *L,int n){
  if(L!=NULL){
   AdjList *p=(AdjList *)malloc(sizeof(AdjList));
   p->next=L->next;
   p->data=n;
   L->next=p;

  }else{
    printf("連結串列為空\n");
  }
}
//刪除鏈首
void deleteTail(AdjList *L){
  if(L!=NULL){
   AdjList *p=L;
   while(p->next->next!=NULL){
     p=p->next;
   }
   p->next=NULL;
  }else{
    printf("連結串列為空\n");
  }
}
//查詢n,若在,則調整到隊尾
int CheckChangeTail(AdjList *L,int n){
  if(L!=NULL){
   AdjList *p=L;
   while(p->next!=NULL){
        //printf("連結串列為空\n");
        if(p->next->data==n){
           p->next=p->next->next;
           AddTail(L,n);
           return 1;
        }
        p=p->next;
   }
   return 0;
  }
}
//列印連結串列、
void printTail(AdjList *L){
  if(L!=NULL){
   AdjList *p=L->next;
   printf("列印連結串列:");
   while(p!=NULL){
        printf("%d ",p->data);
        p=p->next;
   }
   printf("\n");
  }
}
//最近最少使用頁面淘汰演算法
void LRU(int A[]){
   int i,num=0,k=0;
   AdjList *L=(AdjList *)malloc(sizeof(AdjList));
   L->next=NULL;
   for(i=0;i<M;i++){
       //printf("連結串列為空\n");
      if(CheckChangeTail(L,A[i])==1){
        num++;
      }else{
        if(k<ASSIGN){
          AddTail(L,A[i]);
        }else{
          deleteTail(L);
          AddTail(L,A[i]);
        }
        k++;
      }
      printTail(L);
   }
   printf("LRU的命中率為%f\n",(float)num/M);
}
int main(){
   int i,A[N];
   for(i=0;i<M;i++){//隨機產生個M個程序作業數,沒次呼叫的頁面在1-8之間
     A[i]=rand()%8+1;
     printf("%d ",A[i]);
   }
   printf("\n");
   FIFO(A);
   LRU(A);
}