【操作系統】處理機調度算法

實驗3 處理機管理

一、實驗目的

在多道程序或多任務系統中,系統中同時處于就緒態的進程有若干個,即能運行的進程數遠遠大于處理機個數。為了使系統中的各個進程能有條不紊的運行,必須按照某種調度策略,選擇一個進程占用處理機。

本次實驗要求設計并實現一個模擬單處理機調度的算法,以加深對處理機調度基本概念和基本算法的理解。

二、實驗內容

1、設計一個按時間片輪轉法實現處理機調度的程序(難度系數0.95)

?????? (1)假設系統中有N個進程,每個進程由一個進程控制塊(PCB)來標識,進程控制塊結構如下圖所示。

進程名

到達時間

估計運行時間

進程狀態

……

鏈接指針

圖1 進程控制塊PCB結構圖

?

???????進程名:即進程標識。

?????? 到達時間:進程創建時的系統時間或由用戶制定。

估計運行時間:可由設計者指定一個時間值。

?????? 進程狀態:這里假定進程有兩種狀態:就緒狀態和完成狀態。就緒狀態用“R”表示,完成狀態用“C”表示。假定進程創建后就處于就緒狀態,運行結束時,就被置成完成狀態。

鏈接指針:按照進程到達系統的時間將處于就緒狀態的進程連接成一個就緒隊列。指針指出下一個到達的進程控制塊首地址。最后一個進程的鏈指針為NULL。

???????(2)按照進程到達的先后順序排成一個循環隊列。

?????? (3)執行處理機調度時,首先選擇隊首的第一個進程運行。

?????? (4)由于本實驗是模擬實驗,所以對被選中進程并不實際啟動運行,而只是執行:

????????????????? 估計運行時間減1,用這個操作來模擬進程的一次運行。

?????? (5)進程運行一次后,以后的調度則將當前指針依次下移一個位置,指向下一個進程。同時還應判斷該進程的剩余運行時間是否為0,若不為0,則等待下一輪的運行;若該進程的剩余運行為0,則將該進程的狀態置為完成狀態,并退出循環隊列。

?????? (6)若就緒隊列不空,則重復上述的步驟(4)和(5)直到所有進程都運行完為止。

?????? (7)在所設計的調度程序中,應包含顯示或打印語句,以便顯示或打印每次選中進程的名稱及運行一次后隊列的變化情況。

?????? (8)計算每個進程的周轉時間、帶權周轉時間以及進程平均周轉時間。

2、設計一個按優先級調度的算法實現處理機調度(難度系數1.0)

(1) 系統有N個進程,每個進程用一個進程控制塊來代表,進程控制塊的結構如下圖所示。

進程名

到達時間

估計運行時間

進程優先級

進程狀態

……

鏈接指針

圖2 進程控制塊PCB結構

進程的優先級、要求運行時間和估計運行時間由用戶程序任意設定。調度時,總是選擇優先級最高的進程運行。

(2)為了調度方便,設計一個指針指向就緒隊列中的第一個進程。另外再設一個當前運行進程指針,指向當前正運行的進程。

(3)處理機每個時間片調度1次,總是選擇已經到達隊列的優先級最高的進程運行。為了采用動態優先級調度,進程每運行一次,其優先級就減1。由于本實驗是模擬實驗,所以對選中進程并不實際啟動運行,而只是執行:

優先級減1和估計運行時間減1,用這兩個操作來模擬進程的一次運行。

(4)進程運行一次后,若剩余時間不為0,且其優先級低于就緒隊列的其他進程優先級,則選擇一個高優先級進程搶占CPU;若剩余時間為0,把它的狀態改為完成狀態“C”,并撤出就緒隊列。

(5)若就緒隊列不空,則重復上述的步驟(3)和(4),直到所有進程成為完成狀態。

(6)在所設計的調度程序中,應包含顯示或打印語句,以便顯示或打印每次選中進程的名稱及運行一次后隊列的變化情況。

?????? (7)計算每個進程的周轉時間、帶權周轉時間以及進程平均周轉時間。

三、實驗結果和分析

(1)程序中使用的數據結構說明;

【1】實驗內容1使用的數據結構說明:

如上圖所示,進程控制塊使用結構體進行構建,包含以下幾個屬性:進程名字、進程狀態、就緒隊列中的累計排隊序號、進程到達時間、進程服務時間、進程完成時間、進程剩余時間。其中,進程名字使用字符串變量,其他屬性均使用整形變量。

如上圖所示,在執行RR算法之前,首先利用字符串存放當前的就緒隊列,利用數組list存放在就緒隊列中的進程的編號,利用數組waitnumber存放進程在就緒隊列中的累計排隊序號。然后,通過對數組waitnumber進行從小到大的排序,同時對應給數組list進行排序。最后,在數組list中得到按照等待順序遞增的進程序列,并將進程名字按序寫入ready中。

【2】實驗內容2使用的數據結構說明:

如上圖所示,進程控制塊使用結構體進行構建,包含以下幾個屬性:進程名字、進程狀態、進程到達時間、進程服務時間、進程完成時間、進程剩余時間、進程優先級、進程上一次變為就緒態的時間。其中,進程名字使用字符串變量,其他屬性均使用整形變量。此外,進程上一次變為就緒態的時間初始化為進程到達時間,如果進程后續有被CPU調用,則更新為被CPU調用后的時間。

如上圖所示,在執行PSA算法之前,首先利用數組存放當前的就緒隊列所對應的進程編號,并調用sortlist()函數進行當前時間的就緒隊列計算。

(2)程序流程圖和帶有注釋的源程序;

【1】實驗內容1的流程圖:如(4)處的總結1所示,并主要包含以下四個內容:

1)整體的程序流程圖;

2)進程初始化的流程圖;

3)按照到達時間排序進程的流程圖;

4)時間片輪轉算法的流程圖。

【2】實驗內容2的流程圖:如(4)處的總結2所示,并主要包含以下四個內容:

1)整體的程序流程圖;

2)進程初始化的流程圖;

3)就緒隊列進行排序的流程圖;

4)優先級調度算法的流程圖。

【3】實驗內容1 & 實驗內容2的帶有注釋的源程序:

實驗內容1:exp3-1.cpp

#include <iostream>

#include <stdio.h>

#include <iomanip>

#include <string.h>

#include <stdlib.h>

using namespace std;

//pcb的結構體設置

typedef struct{

? ? string name; ? ? ? ?//進程名字

? ? int flag; ? ? ? ? ? //是否完成,狀態檢測(1是完成,0是未完成)

? ? int number; ? ? ? ? //就緒隊列中的順序

? ? int arrivetime; ? ? //到達時間

? ? int runtime; ? ? ? ?//服務時間

? ? int completetime; ? //完成時間

? ? int remaintime; ? ? //剩余時間

}PCB;

//進程指標 (全局)

PCB p[100]; ? ? ? ? ? ? //可輸入的進程數量

int timelen=1; ? ? ? ? ?//時間片長度

int total; ? ? ? ? ? ? ?//進程總數(由main中的用戶輸入)

//就緒隊列指標 (全局)

int current=0; ? ? ? ? ?//當前應該執行的進程編號

int head=0; ? ? ? ? ? ? //就緒隊列中的隊首

//進程初始化

void initialize(){

? ? for(int i=0;i<total;i++){

? ? ? ? cout<<"請輸入第"<<i+1<<"個進程的名字、到達時間、服務時間:";

? ? ? ? cin>>p[i].name>>p[i].arrivetime>>p[i].runtime;

? ? ? ?

? ? ? ? //其他屬性的初始化

? ? ? ? p[i].remaintime=p[i].runtime; ? //初始剩余時間 = 服務時間

? ? ? ? p[i].flag=0; ? ? ? ? ? ? ? ? ? ?//完成狀態 = 未完成

? ? ? ? p[i].number=0; ? ? ? ? ? ? ? ? ?//就緒隊列中的順序 = 0

? ? }

}

//按照到達時間排序進程(冒泡排序)

void sortarrive(){

? ? for(int i=0;i<total-1;i++){

? ? ? ? for(int j=0;j<total-i-1;j++){

? ? ? ? ? ? //到達時間從小到大排序

? ? ? ? ? ? if(p[j].arrivetime>p[j+1].arrivetime){

? ? ? ? ? ? ? ? //如果前一個的時間大于后一個,則交換兩個進程的順序

? ? ? ? ? ? ? ? PCB t=p[j+1];

? ? ? ? ? ? ? ? p[j+1]=p[j];

? ? ? ? ? ? ? ? p[j]=t;

? ? ? ? ? ? }

? ? ? ? }

? ? }

}

//時間片輪轉

void timeprocess(){

? ? int time=p[0].arrivetime; ? ? ? ? ? //系統開始的時間是最早就緒進程的到達時間

? ? int complete=0; ? ? ? ? ? ? ? ? ? ? //已經完成的進程個數

? ? int n=0; ? ? ? ? ? ? ? ? ? ? ? ? ? ?//記錄while循環次數的變量

? ?

? ? //所有進程執行的過程

? ? while(complete<total){

? ? ? ? for(int i=0;i<total;i++){

? ? ? ? ? ? //當前這個進程和cur相同,且狀態為未完成

? ? ? ? ? ? if(p[i].number==current && p[i].flag==0){

? ? ? ? ? ? ? ? //print current cycle

? ? ? ? ? ? ? ? cout<<endl<<"當前的時鐘周期是:T"<<current<<endl;

? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ? //process ready list

? ? ? ? ? ? ? ? string ready="";

? ? ? ? ? ? ? ? int list[100];

? ? ? ? ? ? ? ? int waitnumber[100];

? ? ? ? ? ? ? ? int cnt=0;

? ? ? ? ? ? ? ? for(int k=0;k<total;k++){

? ? ? ? ? ? ? ? ? ? //大于當前current的,都是在就緒隊列里面的進程

? ? ? ? ? ? ? ? ? ? if(p[k].number>current && p[k].flag==0){

? ? ? ? ? ? ? ? ? ? ? ? list[cnt]=k;

? ? ? ? ? ? ? ? ? ? ? ? waitnumber[cnt]=p[k].number;

? ? ? ? ? ? ? ? ? ? ? ? cnt++;

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? cout<<"就緒隊列里面一共有:"<<cnt<<"個進程,";

? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ? //按照waitnumber排序 (冒泡排序)

? ? ? ? ? ? ? ? for (int k = 0; k < cnt - 1; k++) {

? ? ? ? ? ? ? ? ? ? for (int kk = 0; kk < cnt - 1 - k; kk++) {

? ? ? ? ? ? ? ? ? ? ? ? if (waitnumber[kk] > waitnumber[kk + 1]) {

? ? ? ? ? ? ? ? ? ? ? ? ? ? int tempfig = waitnumber[kk + 1];

? ? ? ? ? ? ? ? ? ? ? ? ? ? waitnumber[kk + 1] = waitnumber[kk];

? ? ? ? ? ? ? ? ? ? ? ? ? ? waitnumber[kk] = tempfig;

? ? ? ? ? ? ? ? ? ? ? ? ? ? int templist = list[kk + 1];

? ? ? ? ? ? ? ? ? ? ? ? ? ? list[kk + 1] = list[kk];

? ? ? ? ? ? ? ? ? ? ? ? ? ? list[kk] = templist;

? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? }//不知道為啥死循環了。。調好了

? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ? //按照waitnumber的大小進行push

? ? ? ? ? ? ? ? for(int k=0;k<cnt;k++){

? ? ? ? ? ? ? ? ? ? int id=list[k];

? ? ? ? ? ? ? ? ? ? ready+=p[id].name;

? ? ? ? ? ? ? ? ? ? ready+=" ";

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? //print ready

? ? ? ? ? ? ? ? if(ready==""){

? ? ? ? ? ? ? ? ? ? cout<<"就緒隊列為空"<<endl;

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? else{

? ? ? ? ? ? ? ? ? ? cout<<"當前的就緒隊列為:"<<ready<<endl;

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ? //時間片工作

? ? ? ? ? ? ? ? cout<<"判斷時間片ing,當前應該執行進程"<<p[i].name<<endl;

? ? ? ? ? ? ? ? //current進程能在當前時間片運行完

? ? ? ? ? ? ? ? if(p[i].remaintime<=timelen){

? ? ? ? ? ? ? ? ? ? time+=p[i].remaintime; ? ? ?//系統時間,增加該進程的剩余時間

? ? ? ? ? ? ? ? ? ? p[i].flag=1; ? ? ? ? ? ? ? ?//狀態變為完成

? ? ? ? ? ? ? ? ? ? p[i].completetime=time; ? ? //此進程的完成時間為當前系統時間

? ? ? ? ? ? ? ? ? ? p[i].remaintime=0; ? ? ? ? ?//剩余時間,設置為0

? ? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ? ? ? complete++; ? ? //系統中完成的進程數+=1

? ? ? ? ? ? ? ? ? ? current++; ? ? ?//cur+=1

? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ? ? ? //檢查是否有新的到達進程

? ? ? ? ? ? ? ? ? ? for(int j=i+1;j<total;j++){

? ? ? ? ? ? ? ? ? ? ? ? //有新的到達進程

? ? ? ? ? ? ? ? ? ? ? ? if(p[j].arrivetime<=time && p[j].number==0){

? ? ? ? ? ? ? ? ? ? ? ? ? ? head++; ? ? ? ? ? ? //就緒隊列個數+=1

? ? ? ? ? ? ? ? ? ? ? ? ? ? p[j].number=head; ? //這個進程的就緒編號為head

? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? //current進程不能在當前時間片運行完

? ? ? ? ? ? ? ? else{

? ? ? ? ? ? ? ? ? ? time+=timelen;

? ? ? ? ? ? ? ? ? ? p[i].remaintime-=timelen;

? ? ? ? ? ? ? ? ? ? current++;

? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ? ? ? //檢查是否有新的到達進程

? ? ? ? ? ? ? ? ? ? for(int j=i+1;j<total;j++){

? ? ? ? ? ? ? ? ? ? ? ? if(p[j].arrivetime<=time && p[j].number==0){

? ? ? ? ? ? ? ? ? ? ? ? ? ? head++;

? ? ? ? ? ? ? ? ? ? ? ? ? ? p[j].number=head;

? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ? ? ? //重新給這個進程加入就緒隊列

? ? ? ? ? ? ? ? ? ? head++; ? ? ? ? ? ? //剛剛執行的這個進程繼續進入就緒隊列

? ? ? ? ? ? ? ? ? ? p[i].number=head; ? //更改就緒編號

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ?

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? n++; ? ?//檢測while循環的次數

? ? }

? ? cout<<"執行完畢,總共花費時鐘周期:T"<<current<<endl;

}

void show(){

? ? double x=0; ? ? //總周轉時間 ? ? ? ? 周轉時間 = 完成時間 - 到達時間

? ? double y=0; ? ? //總帶權周轉時間 ? 帶權周轉時間 = 周轉時間 / 服務時間

? ?

? ? //輸出每個進程的基本信息

? ? for(int i=0;i<total;i++){

? ? ? ? double px=(double)p[i].completetime-p[i].arrivetime; ? ?//當前進程的周轉時間

? ? ? ? double py=px/(double)p[i].runtime; ? ? ? ? ? ? ? ? ? ? ?//當前進程的帶權周轉時間

? ? ? ? cout<<"進程名字:"<<p[i].name;

? ? ? ? cout<<"\t"<<"周轉時間:"<<px;

? ? ? ? cout<<"\t"<<"帶權周轉時間:"<<py;

? ? ? ? cout<<"\t"<<"到達時間:"<<p[i].arrivetime;

? ? ? ? cout<<"\t"<<"服務時間:"<<p[i].runtime;

? ? ? ? cout<<"\t"<<"完成時間:"<<p[i].completetime;

? ? ? ? cout<<endl;

? ? ? ? x+=px;

? ? ? ? y+=py;

? ? }

? ? double ret1=x/total; ? ?//平均周轉時間

? ? double ret2=y/total; ? ?//平均帶權周轉時間

? ? cout<<"平均周轉時間:"<<ret1<<endl;

? ? cout<<"平均帶權周轉時間:"<<ret2<<endl;

}

/*

//RR

測試用例1

5

p1 0 3

p2 2 6

p3 4 4

p4 6 5

p5 8 2

//優先級

測試用例2

4

p1 0 2 2

p2 0 2 3

p3 0 4 1

p4 0 3 4

進程執行的順序應該是:p4 p2 p4 p1 p2 p4 p3 p1 p3 p3 p3

7.5

2.8125

*/

int main(){

? ? cout<<"請輸入進程總數:";

? ? cin>>total; ? ? ? ? //用戶輸入進程的總數

? ? initialize(); ? ? ? //初始化

? ? sortarrive(); ? ? ? //到達時間處理

? ? timeprocess(); ? ? ?//時間片處理

? ? cout<<endl;

? ? show(); ? ? ? ? ? ? //輸出最終的結果

? ? return 0;

}

實驗內容2:exp3-2.cpp

#include <iostream>

#include <stdio.h>

#include <iomanip>

#include <string.h>

#include <stdlib.h>

#include <vector>

using namespace std;

//pcb的結構體設置

typedef struct{

? ? string name; ? ? ? ?//進程名字

? ? int flag; ? ? ? ? ? //是否完成,狀態檢測(1是完成,0是未完成)

? ? int arrivetime; ? ? //到達時間

? ? int runtime; ? ? ? ?//服務時間

? ? int completetime; ? //完成時間

? ? int remaintime; ? ? //剩余時間

? ? int prior; ? ? ? ? ?//優先級

? ? int lasttime; ? ? ? //上一次運行的時間

}PCB;

//進程指標 (全局)

PCB p[100]; ? ? ? ? ? ? //可輸入的進程數量

int timelen=1; ? ? ? ? ?//時間片長度

int total; ? ? ? ? ? ? ?//進程總數(由main中的用戶輸入)

//進程初始化

void initialize(){

? ? for(int i=0;i<total;i++){

? ? ? ? cout<<"請輸入第"<<i+1<<"個進程的名字、到達時間、服務時間、優先級:";

? ? ? ? cin>>p[i].name>>p[i].arrivetime>>p[i].runtime>>p[i].prior;

? ? ? ?

? ? ? ? //其他屬性的初始化

? ? ? ? p[i].remaintime=p[i].runtime; ? //初始剩余時間 = 服務時間

? ? ? ? p[i].flag=0; ? ? ? ? ? ? ? ? ? ?//完成狀態 = 未完成

? ? ? ? p[i].lasttime=p[i].arrivetime; ?//上一次運行的時間

? ? }

}

//初始化就緒隊列

void sortlist(vector<int> &wait,int cycle){

? ? //遍歷已經到來且未完成的進程

? ? for(int i=0;i<total;i++){

? ? ? ? if(p[i].arrivetime<=cycle && p[i].flag==0){

? ? ? ? ? ? wait.push_back(i);

? ? ? ? }

? ? }

? ?

? ? int n=wait.size();

? ? //按照prior劃分(選擇排序)

? ? for(int i=0;i<n-1;i++){

? ? ? ? int id=i; ? //max to process

? ? ? ? for(int j=i+1;j<n;j++){

? ? ? ? ? ? int curprocess=wait[j]; ? ? //遍歷到的后面的進程序號

? ? ? ? ? ? int maxprocess=wait[id]; ? ?//當前優先級最大的進程序號

? ? ? ? ? ? if(p[maxprocess].prior<p[curprocess].prior){

? ? ? ? ? ? ? ? //如果后面進程的prior更大,則更新優先級最大的進程序號

? ? ? ? ? ? ? ? id=j;

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? if(id!=i){

? ? ? ? ? ? //如果有更新,則交換兩個pcb的順序

? ? ? ? ? ? int t=wait[id];

? ? ? ? ? ? wait[id]=wait[i];

? ? ? ? ? ? wait[i]=t;

? ? ? ? }

? ? }

? ?

? ? //相同prior按照lasttime劃分

? ? int i=0; ? ?//從隊首開始分析

? ? while(i<n-1){

? ? ? ? int pos=i; ?//記錄離當前最遠,且和當前進程優先級相同的進程

? ? ? ? int nowid=wait[i];

? ? ? ? for(int j=1+i;j<n;j++){

? ? ? ? ? ? int processid=wait[j];

? ? ? ? ? ? if(p[processid].prior==p[nowid].prior){

? ? ? ? ? ? ? ? pos=j; ?//后面的進程和現在的進程優先級相同,更新最遠記錄

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? if(pos!=i){

? ? ? ? ? ? //sort between wait[i] and wait[pos] according to lasttime(選擇排序)

? ? ? ? ? ? for(int a=i;a<pos;a++){

? ? ? ? ? ? ? ? int aid=a;

? ? ? ? ? ? ? ? for(int b=a+1;b<=pos;b++){

? ? ? ? ? ? ? ? ? ? int cur=wait[b];

? ? ? ? ? ? ? ? ? ? int min=wait[aid];

? ? ? ? ? ? ? ? ? ? if(p[min].lasttime>p[cur].lasttime){

? ? ? ? ? ? ? ? ? ? ? ? //如果后面的lasttime更小

? ? ? ? ? ? ? ? ? ? ? ? aid=b;

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? if(aid!=a){

? ? ? ? ? ? ? ? ? ? //如果有更新,則交換兩個pcb的順序

? ? ? ? ? ? ? ? ? ? int tt=wait[aid];

? ? ? ? ? ? ? ? ? ? wait[aid]=wait[a];

? ? ? ? ? ? ? ? ? ? wait[a]=tt;

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? i=pos+1; ? ?//移動到下一個還沒有判斷過優先級是否相等的pcb

? ? }

}

void psa(){

? ? //系統開始時間 (初始化)

? ? int starttime=p[0].arrivetime;

? ? for(int i=1;i<total;i++){

? ? ? ? if(starttime>p[i].arrivetime){

? ? ? ? ? ? starttime=p[i].arrivetime; ?//更新進程最早到達的時間

? ? ? ? }

? ? }

? ?

? ? int cycle=0; ? ? ? ?//執行的周期數

? ? int complete=0; ? ? //完成的進程數

? ?

? ? //執行所有進程

? ? while(complete<total){

? ? ? ? //wait list

? ? ? ? vector<int> wait;

? ? ? ? sortlist(wait,cycle);

? ? ? ? cout<<endl<<"在執行該時間片前,T"<<cycle<<"的就緒隊列為:";

? ? ? ? for(int i=0;i<wait.size();i++){

? ? ? ? ? ? int proid=wait[i];

? ? ? ? ? ? cout<<p[proid].name<<" ";

? ? ? ? }

? ? ? ? cout<<endl;

? ? ? ?

? ? ? ? //執行wait[0](位于就緒隊列隊首的時間片)

? ? ? ? int curpro=wait[0];

? ? ? ? cout<<"判斷時間片ing,當前應該執行進程:"<<p[curpro].name<<endl;

? ? ? ?

? ? ? ? //判斷當前時間片內,curpro是否能執行完畢

? ? ? ? if(p[curpro].remaintime<=timelen){ ?

? ? ? ? ? ? //can

? ? ? ? ? ? p[curpro].flag=1; ? ? ? ? ? ? ? ? ? ? ? ? ? //修改進程狀態,且flag==1之后,就不需要管prior

? ? ? ? ? ? p[curpro].completetime=starttime+cycle+1; ? //修改完成時間

? ? ? ? ? ? p[curpro].remaintime=0; ? ? ? ? ? ? ? ? ? ? //修改剩余時間

? ? ? ? ? ? complete++; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //完成的進程數 += 1

? ? ? ? ? ? cout<<"在這個時間片內,已經執行完進程:"<<p[curpro].name<<endl;

? ? ? ? }

? ? ? ? else{ ?

? ? ? ? ? ? //cannot

? ? ? ? ? ? p[curpro].remaintime-=timelen; ?//修改剩余時間

? ? ? ? ? ? p[curpro].prior--; ? ? ? ? ? ? ?//修改優先級

? ? ? ? ? ? p[curpro].lasttime=cycle+1; ? ? //修改上次使用時間

? ? ? ? }

? ? ? ?

? ? ? ? cycle++; ? ?//時間周期 += 1

? ? ? ? //complete++; ? //temporary break while to debug

? ? }

? ? cout<<endl<<"執行完畢,總共花費時鐘周期:T"<<cycle<<endl;

}

void show(){

? ? double x=0; ? ? //總周轉時間 ? ? ? ? 周轉時間 = 完成時間 - 到達時間

? ? double y=0; ? ? //總帶權周轉時間 ? 帶權周轉時間 = 周轉時間 / 服務時間

? ?

? ? //輸出每個進程的基本信息

? ? for(int i=0;i<total;i++){

? ? ? ? double px=(double)p[i].completetime-p[i].arrivetime; ? ?//當前進程的周轉時間

? ? ? ? double py=px/(double)p[i].runtime; ? ? ? ? ? ? ? ? ? ? ?//當前進程的帶權周轉時間

? ? ? ? cout<<"進程名字:"<<p[i].name;

? ? ? ? cout<<"\t"<<"周轉時間:"<<px;

? ? ? ? cout<<"\t"<<"帶權周轉時間:"<<py;

? ? ? ? cout<<endl;

? ? ? ? cout<<"\t"<<"到達時間:"<<p[i].arrivetime;

? ? ? ? cout<<"\t"<<"服務時間:"<<p[i].runtime;

? ? ? ? cout<<"\t"<<"完成時間:"<<p[i].completetime;

? ? ? ? cout<<endl;

? ? ? ? x+=px;

? ? ? ? y+=py;

? ? }

? ? double ret1=x/total; ? ?//平均周轉時間

? ? double ret2=y/total; ? ?//平均帶權周轉時間

? ? cout<<"平均周轉時間:"<<ret1<<endl;

? ? cout<<"平均帶權周轉時間:"<<ret2<<endl;

}

/*

//優先級

測試用例2

4

p1 0 2 2

p2 0 2 3

p3 0 4 1

p4 0 3 4

進程執行的順序應該是:p4 p2 p4 p1 p2 p4 p3 p1 p3 p3 p3

? ? ? ? ? ? ? ? ? ? ? 0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9 ?10

7.5

2.8125

*/

int main(){

? ? cout<<"請輸入進程總數:";

? ? cin>>total; ? ? ? ? //用戶輸入進程的總數

? ? initialize(); ? ? ? //初始化

? ? psa(); ? ? ? ? ? ? ?//psa process

? ? cout<<endl;

? ? show(); ? ? ? ? ? ? //輸出最終的結果

? ? return 0;

}

?

(3)執行程序名,并打印程序運行時的初值和運行結果,其中包括:

??? ①各進程控制塊的初始狀態;

【實驗內容1】

在本實驗內容中,測試用例的內容如下表所示。

進程總數

5

進程名字

進程到達時間

進程服務時間

P1

0

3

P2

2

6

P3

4

4

P4

6

5

P5

8

2

?如下圖所示,在初始化函數initialize()中,在初始化各個進程的各個屬性之后,將打印各個進程的基本信息(完成時間除外)。

測試用例的結果如下圖所示。

由上圖可知,進程初始化成功,各個進程控制塊的初始狀態符合預期。

【實驗內容2】

在本實驗內容中,測試用例的內容如下表所示。

進程總數

4

進程名字

進程到達時間

進程服務時間

進程優先級

P1

0

2

2

P2

0

2

3

P3

0

4

1

P4

0

3

4

如下圖所示,在初始化函數initialize()中,在初始化各個進程的各個屬性之后,將打印各個進程的基本信息(完成時間除外)。

測試用例的結果如下圖所示。

由上圖可知,進程初始化成功,各個進程控制塊的初始狀態符合預期。

??? ②選中運行進程的名字、運行后各進程控制塊狀態以及每次調度時,就緒隊列的進程排列順序;

【實驗內容1】

在RR算法執行過程中,程序會輸出當前的時間、就緒隊列的結果、當前時間片選中運行進程的名字、當前時間片運行后執行完畢的進程,并在算法執行完畢后輸出系統總花費的時間。程序輸出的結果如下圖所示。

在PSA算法執行完畢后,程序會輸出各個進程的周轉時間和帶權周轉時間,并同時輸出到達時間、服務時間、完成時間,以便核對計算是否正確。在輸出完所有進程的信息后,程序會輸出系統的平均周轉時間和平均帶權周轉時間。程序輸出的結果如下圖所示。

核驗實驗3的ppt中關于RR算法的測試案例后,發現實驗結果和理論計算結果一致。

【實驗內容2】

在PSA算法執行過程中,程序會輸出就緒隊列的結果、當前時間片選中運行進程的名字、當前時間片運行后執行完畢的進程,并在算法執行完畢后輸出系統總花費的時間。程序輸出的結果如下圖所示。

在PSA算法執行完畢后,程序會輸出各個進程的周轉時間和帶權周轉時間,并同時輸出到達時間、服務時間、完成時間,以便核對計算是否正確。在輸出完所有進程的信息后,程序會輸出系統的平均周轉時間和平均帶權周轉時間。

核驗實驗3的ppt中關于PSA算法的測試案例后,發現實驗結果和理論計算結果一致。

4總結本次實驗的心得與體會。

【流程圖】

1:實驗內容1的流程圖

1)整體的程序流程圖(main函數)

2)進程初始化的流程圖(initialize函數)

3)按照到達時間排序進程的流程圖(sortarrive函數)

4)時間片輪轉算法的流程圖

5)運行結果輸出的流程圖(show函數)

2:實驗內容2的流程圖

注:運行結果輸出的流程圖(show函數)與實驗內容1相同,此處不再贅述。

1)整體的程序流程圖

2)進程初始化的流程圖

3)就緒隊列進行排序的流程圖

4)優先級調度算法的流程圖

【實驗總結】

3時間片原則:各進程按時間片運行,當一個時間片用完后,便停止該進程的執行而重新調度,適用于分時系統。

4優先權原則:通常對一些重要的和緊急的進程賦予較高的優先權。當這種進程進入就緒隊列時,如果其優先權比正在執行的進程優先權高,便停止正在執行的進程,將處理機分配給優先權高的進程。

5:進程調度方式分為兩種——【搶占方式】和【非搶占方式】。搶占方式:把處理機分配給某進程后便讓它一直運行下去,直到進程完成或發生某事件而阻塞時,才把處理機分配給另一個進程。非搶占方式:當一個進程正在運行時,系統可以基于某種原則,剝奪已分配給它的處理機,將之分配給其它進程。因此,時間片輪轉法(RR)和優先級調度算法(PSA)均是搶占方式,因為這兩種算法都并沒有一個進程完整地運行。

6:各種調度算法的優點和缺點如下圖所示。

FCFS:先來先服務算法。

SJF:最短作業優先算法。

HRRF:最高響應比優先算法。

RR:時間片輪轉算法。

7:在本實驗中,主要使用了RR和PSA。RR的特點是:公平性高,每個進程都有機會執行;可能導致較高的上下文切換開銷,實時性較差。PSA的特點是:能夠更好地滿足緊急任務的需要,對于重要或緊急的任務更加有效;可能導致低優先級進程長時間等待,甚至發生饑餓現象。

8饑餓現象:在操作系統中是指某一個或多個進程由于種種原因長時間得不到所需的資源,從而無法繼續執行的情況。

四、實驗指導

?????? 在Linux環境下, 用C語言編寫,程序中的數據結構定義和程序主框架如下,供參考。

??

?????? typedef?? struct? pcb????????? //進程控制塊定義

?????? {? ? int? pid; ??????????//進程ID

char? pname[N];????????? //進程名

????????????? int? runtime;??????????????? //運行時間

????????????? int? arrivetime;??????????? //到達時間

????????????? char state;??????????????????? //進程狀態

????????????? int? priority;??????????????? //進程優先級

int?? finishtime;???????????? //進程結束時間

????????????? struct? pcb? *next;????? //鏈接指針

??????? ……

}? PCB;

PCB? *head_input;???????????? //就緒隊列頭指針

PCB? *head_run;??????????????? //運行進程指針

unsigned long current;????? //記錄系統當前時間的變量

……

void? inputprocess( );? //建立進程,輸入進程數目N,輸入各個進程信息,并建立鏈表;

void? printreadylist( );? //輸出就緒隊列

int?? readyprocess( ); //檢查就緒隊列并運行進程

int?? runprocess( );? //運行進程的函數;

……

void main()?????????? //主函數

{? ? //fp=open("result.txt”, “w”);

??? current=0;

?????? inputprocess( );

????? readyprocess( );

??? ……

?????? getch( );

?????? //fclose(fp);

}

void? inputprocess( )? //建立進程,輸入進程數目N,輸入各個進程信息,并建立鏈表;

{ // 輸入需要運行的進程數量n

??…..

? // 輸入進程信息:進程名,運行時間,到達時間,優先級等信息

??…...

}

int ?readyprocess( )????? //檢查就緒隊列并運行進程

{ // 就緒隊列為空時,結束運行

??…..

?// 根據調度算法選擇一個進程;

runprocess();

//如果是時間片調度算法,則將時間減1

//如果是FCFS調度算法,則該進程運行結束,將當前時間+運行時間

//如果是優先級調度算法,運行時間-1,優先級-1

// 修改進程的狀態

?……

?// 輸出進程運行信息

}

五、測試用例

1. 時間片調度算法

2 優先級調度算法

進程?????? 優先級????????? 運行時間?????? 到達時間?? ?結束時間

P1????? 12? ????????? 2???????? 0??????????? 8

P2????? 13????????? ? 2???????? 0??????????? 5

P3????? 11??????????? 4???????? 0??????????? 11

P4????? 14????????? ? 3???? ??? 0??????????? 6

程序執行過程:

每個時間片調度一次,執行完成的進程優先級減1,重新調度

0?? ??1? ???2???? 3? ???4? ???5?? ??6?? ??7?? ??8?? ??9?? ??10???? time

P4-——p2——p4——p1——P2——p4——p3——p1——p3——p3——p3

13? ??12? ??12? ??11? 11end ??11end 10 ???10end ?9? ??8? ???7end

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/697822.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/697822.shtml
英文地址,請注明出處:http://en.pswp.cn/news/697822.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

使用puppeteer完成監聽瀏覽器下載文件并保存到自己本地或服務器上完成上傳功能

需求場景 獲取網站點擊的下載pdf&#xff0c;并把pdf重命名再上傳到COS云上面 技術使用 “puppeteer”: “^19.7.2”, “egg”: “^3.15.0”, // 服務期用egg搭的 文件服務使用COS騰訊云 核心思路 獲取瀏覽器下載事件&#xff0c;并把文件保存到本地 const session awai…

Unity3D 框架如何搭建基于純Lua的U框架與開發模式詳解

前言 Unity3D 是一款非常流行的游戲開發引擎&#xff0c;它支持C#、JavaScript和Boo等多種腳本語言。而Lua語言作為一種輕量級的腳本語言&#xff0c;也在游戲開發中得到了廣泛應用。本文將介紹如何在Unity3D框架中搭建基于純Lua的U框架&#xff0c;并詳細講解其開發模式。 對…

MYSQL--存儲過程操作

一&#xff1a;概念&#xff1a; 存儲過程實際上對標了JAVA當中的方法&#xff0c;兩者是相似的&#xff0c;同時需要注意的一點是&#xff0c;MYSQL僅僅在5.0版本之后才出現這種存儲操作的過程&#xff1b; 優點&#xff1a; 1.存儲過程能夠讓運行的速度變得更加迅速&#xff…

SpringBoot指定外部環境配置

nohup java -Xms256m -Xmx512m -Dfile.encodingUTF-8 -jar /usr/local/xxxx.jar --spring.profiles.activeprod > system.log 2>&1 & --spring.profiles.activeprod修改的是多環境配置中內部application.properties里的spring.profiles.active值 -Dspring.config…

ubuntu 查詢流量使用

在Ubuntu系統中&#xff0c;可以使用nethogs命令來查看每個進程的網絡流量使用情況。這個工具可以顯示每個進程的實時網絡流量&#xff0c;從而可以找出使用流量最多的應用。 首先&#xff0c;你需要安裝nethogs。在終端中輸入以下命令&#xff1a; sudo apt install nethogs…

消息隊列MQ 保證消息不丟失(消息可靠性)

文章目錄 概述RabbitMQ 怎么避免消息丟失&#xff08;可靠傳輸&#xff09;RocketMQ 怎么確保消息不丟失Kafka 怎么保證消息不丟失activeMQ 怎么避免消息丟失MQ 宕機了消息是否會丟失線上服務宕機時&#xff0c;如何保證數據100%不丟失嗎&#xff1f;消息隊列消息持久化 概述 …

思偉老友記 | 攜手并進17年 中泰公司的穩步發展和企業傳承

17年攜手并進 合作共贏 2023年是中泰&#xff08;福建&#xff09;混凝土發展有限公司攜手思偉軟件的第17年。在這關鍵的17年間&#xff0c;我們共同經歷了一個行業的興盛發展&#xff0c;也相互見證了彼此的榮耀成長。中泰從泉州惠安洛陽江邊一個簡單的攪拌站&#xff0c;到如…

h-table(表格列表組件的全封裝)

文章目錄 概要h-table的封裝過程查詢組件封裝 h-highForm結果頁右側工具欄封裝RightToolbar結果頁列表組件h-table結果頁vue頁面使用js文件有需要的請私信博主&#xff0c;還請麻煩給個關注&#xff0c;博主不定期更新組件封裝&#xff0c;或許能夠有所幫助&#xff01;&#x…

如何做代幣分析:以 SOL 幣為例

作者&#xff1a;lesleyfootprint.network 編譯&#xff1a;cicifootprint.network 數據源&#xff1a;Solana Token Dashboard &#xff08;僅包括以太坊數據&#xff09; 在加密貨幣和數字資產領域&#xff0c;代幣分析起著至關重要的作用。代幣分析指的是深入研究與代幣…

springmvc基于springboot 的音樂播放系統 _7sdu8

這就意味著音樂播放系統的設計可以比其他系統更為出色的能力&#xff0c;可以更高效的完成最新的ymj排行榜、ymj音樂資訊等功能。 此系統設計主要采用的是JAVA語言來進行開發&#xff0c;JSP技術、采用SSM框架技術&#xff0c;框架分為三層&#xff0c;分別是控制層Controller&…

Seata的 TCC 模式

目錄 概述 使用 依賴與配置 代碼 概述 TCC 模式是一種侵入式的分布式事務解決方案&#xff0c;它不依賴于數據庫的事務&#xff0c;而是要求開發者自定義完成 預提交、提交、回滾的方法邏輯。因此&#xff0c;它是一個種偏 復雜、靈活、有侵入性 的分布式事務處理方案。 De…

針對Umi、React中遇到的 “xxxx”不能用作 JSX 組件 問題解決方案

一、處理方案 這是因為"types/react"、"types/react-dom"在子依賴中使用的版本不一致導致&#xff0c;一般情況npm會自動幫我們處理版本不一致的問題。如果npm處理不了&#xff0c;就需要我們自己手動處理在package.json中添加一項配置 {name:"test&…

Zookeeper選舉Leader源碼剖析

Zookeeper選舉Leader源碼剖析 leader選舉流程 參數說明 myid: 節點的唯一標識&#xff0c;手動設置zxid: 當前節點中最大(新)的事務idepoch-logic-clock: 同一輪投票過程中的邏輯時鐘值相同&#xff0c;每投完一次值會增加 leader選舉流程 默認投票給自己&#xff0c;優先選擇…

vue3 vuex

目錄 Vuex 是什么 什么是“狀態管理模式”&#xff1f; 什么情況下我應該使用 Vuex&#xff1f; 使用方法&#xff1a; 提交載荷&#xff08;Payload&#xff09; 對象風格的提交方式 使用常量替代 Mutation 事件類型 Mutation 必須是同步函數 在組件中提交 Mutation …

redis GEO 類型原理及命令詳解

目錄 前言 一、GeoHash 的編碼方法 二、Redis 操作GEO類型 前言 我們有一個需求是用戶搜索附近的店鋪&#xff0c;就是所謂的位置信息服務&#xff08;Location-Based Service&#xff0c;LBS&#xff09;的應用。這樣的相關服務我們每天都在接觸&#xff0c;用滴滴打車&am…

使用ENV工具編譯RT-Thread【詳細過程講解:從下載到編譯、設置】

感興趣的寶子&#xff0c;可以點個贊收藏&#xff0c;便于后期有需要的時候能快速找到~~ ENV編譯編譯RT-Thread工程的詳細過程講解 ENV簡介ENV的下載設置ENV使用ENV編譯RT-Thread工程◆ 打開ENV◆ 輸入打包命令◆ 查看并打開工程文件◆ 使用menuconfig 對生成項目的RT-Thread配…

【Git企業實戰開發】Git常用開發流操作總結

【Git企業實戰開發】Git常用開發流操作總結 大家好 我是寸鐵&#x1f44a; 總結了一篇Git常用開發流操作總結的文章? 喜歡的小伙伴可以點點關注 &#x1f49d; 現在剛做項目的伙伴&#xff0c;可能你之前學過git&#xff0c;但是一實戰發現不熟悉 沒關系&#xff0c;看寸鐵這篇…

fastadmin引用 redis 方法2

頁面上引用 use \think\cache\driver\Redis; $redis new Redis();$redis->set(key, value);// 獲取鍵值對的值$value $redis->get(key);echo $value;如果執行后出現 不支持redis&#xff0c; 檢查系統是否開啟 redis 擴展。 如果是小皮系統。 項目-管理-php擴展&#x…

js實現頂部導航欄隨著滾動條下滑顯示背景顏色,上劃到頂部背景顏色消失

有個項目需求&#xff0c;如題目所示。這種展示方式讓首頁的內容可以完美展示而不受到導航欄的干擾&#xff0c;等下滑查看內容時導航欄的背景顏色再顯示出來。下面是一個案例&#xff1a; 導航欄隨滑動條下滑顯示 再下面是我的成果視頻展示&#xff1a; 導航條隨滾動條下滑顯示…

vue怎么實現pdf、excel、word文件離線預覽?2024年2月份最新測試(可行方案和詳細代碼在文章末尾)

Vue.js 中實現Office文檔(Word、Excel、PPT)和PDF文件的預覽,通常會借助于第三方庫或服務。 1. Office文檔在線預覽 使用WPS Web Office SDK WPS提供了Web Office服務,可以將文檔轉換為網頁格式進行在線預覽。首先在項目中引入并注冊WPS提供的SDK,然后在Vue組件中配置一個…