從就緒隊列中挑選下一個佔用CPU運行的進程,從多個可用CPU中挑選就緒進程可以使用的CPU資源算法
吞吐量與延遲ide
低延遲:喝水的時候想要一打開水龍頭水就流出來函數
高帶寬:給游泳池充水時但願從水龍頭裏同時流出大量的水,而且不介意是否存在延遲code
依據進程進入就緒狀態的前後順序排列,進程進入等待或結束狀態時,就緒隊列中的下一個進程佔用CPU隊列
可是FCFS的平均等待時間波動較大,I/O資源和CPU資源的利用率較低進程
選擇就緒隊列中執行時間最短進程佔用CPU進入運行狀態,用歷史的執行時間來預估將來的執行時間,短進程優先算法具備最優平均週轉時間資源
可是連續的短進程流會使長進程沒法得到CPU資源rem
選擇就緒隊列中響應比R值最高的進程it
R=(w+s)/s
io
w: 等待時間(waiting time) s: 執行時間(service time)
利用時間片做爲分配處理機資源的基本時間單元,時間片結束時,按FCFS算法切換到下一個就緒進程, 每隔(n – 1)個時間片進程執行一個時間片q
可是時間片輪轉算法須要選擇好時間片的大小,過大太小都會致使效率問題
就緒隊列被劃分紅多個獨立的子隊列,如:前臺–RR、後臺–FCFS
進程可在不一樣隊列間移動的多級隊列算法,時間片大小隨優先級級別增長而增長,如進程在當前的時間片沒有完成,則降到下一個優先級
FSS控制用戶對系統資源的訪問,一些用戶組比其餘用戶組更重要,保證不重要的組沒法壟斷資源,未使用的資源按比例分配,沒有達到資源使用率目標的組得到更高的優先級
這個實驗其實有兩個,一個是實現Round Robin,一個是Stride Scheduling,兩個都很是簡單。
Round Robin調度算法的調度思想是讓全部 runnable 態的進程分時輪流使用 CPU 時間。Round Robin 調度器維護當前 runnable進程的有序運行隊列。當前進程的時間片用完以後,調度器將當前進程放置到運行隊列的尾部,再從其頭部取出進程進行調度。
具體看一下Stride Scheduling
一、爲每一個runnable的進程設置一個當前狀態stride,表示該進程當前的調度權。另外定義其對應的pass值,表示對應進程在調度後,stride 須要進行的累加值。
二、每次須要調度時,從當前 runnable 態的進程中選擇 stride最小的進程調度。對於得到調度的進程P,將對應的stride加上其對應的步長pass(只與進程的優先權有關係)。
三、在一段固定的時間以後,回到步驟2,從新調度當前stride最小的進程
static void stride_init(struct run_queue *rq) { /* LAB6: YOUR CODE */ list_init(&(rq->run_list)); rq->lab6_run_pool = NULL; rq->proc_num = 0; }
首先是隊列初始化函數
static void stride_enqueue(struct run_queue *rq, struct proc_struct *proc) { /* LAB6: YOUR CODE */ #if USE_SKEW_HEAP rq->lab6_run_pool = skew_heap_insert(rq->lab6_run_pool, &(proc->lab6_run_pool), proc_stride_comp_f); #else assert(list_empty(&(proc->run_link))); list_add_before(&(rq->run_list), &(proc->run_link)); #endif if (proc->time_slice == 0 || proc->time_slice > rq->max_time_slice) { proc->time_slice = rq->max_time_slice; } proc->rq = rq; rq->proc_num ++; }
而後是入隊函數stride_enqueue,根據以前對該調度算法的分析,這裏函數主要是初始化剛進入運行隊列的進程 proc 的stride屬性,而後比較隊頭元素與當前進程的步數大小,選擇步數最小的運行,即將其插入放入運行隊列中去,這裏並未放置在隊列頭部。最後初始化時間片,而後將運行隊列進程數目加一。
static void stride_enqueue(struct run_queue *rq, struct proc_struct *proc) { /* LAB6: YOUR CODE */ #if USE_SKEW_HEAP rq->lab6_run_pool = skew_heap_insert(rq->lab6_run_pool, &(proc->lab6_run_pool), proc_stride_comp_f); #else assert(list_empty(&(proc->run_link))); list_add_before(&(rq->run_list), &(proc->run_link)); #endif if (proc->time_slice == 0 || proc->time_slice > rq->max_time_slice) { proc->time_slice = rq->max_time_slice; } proc->rq = rq; rq->proc_num ++; }
static void stride_dequeue(struct run_queue *rq, struct proc_struct *proc) { /* LAB6: YOUR CODE */ #if USE_SKEW_HEAP rq->lab6_run_pool = skew_heap_remove(rq->lab6_run_pool, &(proc->lab6_run_pool), proc_stride_comp_f); //從優先隊列中移除 #else assert(!list_empty(&(proc->run_link)) && proc->rq == rq); list_del_init(&(proc->run_link)); #endif rq->proc_num --; }
static struct proc_struct * stride_pick_next(struct run_queue *rq) { /* LAB6: YOUR CODE */ #if USE_SKEW_HEAP if (rq->lab6_run_pool == NULL) return NULL; struct proc_struct *p = le2proc(rq->lab6_run_pool, lab6_run_pool); #else list_entry_t *le = list_next(&(rq->run_list)); if (le == &rq->run_list) return NULL; struct proc_struct *p = le2proc(le, run_link); le = list_next(le); while (le != &rq->run_list) { struct proc_struct *q = le2proc(le, run_link); if ((int32_t)(p->lab6_stride - q->lab6_stride) > 0) p = q; le = list_next(le); } #endif //更新對應進程的stride值 if (p->lab6_priority == 0) p->lab6_stride += BIG_STRIDE; else p->lab6_stride += BIG_STRIDE / p->lab6_priority; return p; }
接下來就是進程的調度函數stride_pick_next,觀察代碼,它的核心是先掃描整個運行隊列,返回其中stride值最小的對應進程,而後更新對應進程的stride值,將步長設置爲優先級的倒數,若是爲0則設置爲最大的步長。
static void stride_proc_tick(struct run_queue *rq, struct proc_struct *proc) { /* LAB6: YOUR CODE */ if (proc->time_slice > 0) { proc->time_slice --; } if (proc->time_slice == 0) { proc->need_resched = 1; } }
最後是時間片函數stride_proc_tick,主要工做是檢測當前進程是否已用完分配的時間片。
相對於這兩個算法我以爲更重要的是明白進程的調度時機