實驗二 動態高優先權優先調度
實驗內容
模擬實現動態高優先權優先(若數值越大優先權越高,每運行一個時間單位優先權-n,若數值越小優先權越高,沒運行一個時間單位優先權+n),具體如下:
設置進程體:進程名,進程的到達時間,服務時間,初始優先權,進程狀態(W——等待,R——運行,F——完成),進程間的鏈接指針
進程初始化:由用戶輸入進程名、服務時間、初始優先權進行初始化,同時,初始化進程的狀態為W。
顯示函數:在進程調度前、調度中和調度后進行顯示。
排序函數:對就緒狀態的進程按照優先權排序。優先權相同時進入等待隊列時間早的進程在前。注意考慮到達時間
調度函數:每次從等待隊列隊首調度優先權最高的進程執行,狀態變化。並在執行一個時間單位后優先權變化,服務時間變化,狀態變化。當服務時間為0時,狀態變為F。
刪除函數:撤銷狀態為F的進程。
實驗要求
1、 測試數據可以隨即輸入或從文件中讀入。
2、 必須要考慮到進程的到達時間
3、 最終能夠計算每一個進程的周轉時間。
實驗代碼
1.txt
process1 1 5 2 W process2 1 4 7 W process3 1 8 3 W process5 1 6 9 W process4 1 15 6 W
main.go
package main import ( "bufio" "container/heap" "fmt" "os" "strconv" "strings" "time" ) type Item struct { name string priority int index int arrival int service int oldservice int state string } type PriorityQueue []*Item func (pq PriorityQueue) Len() int { return len(pq) } func (pq PriorityQueue) Less(i, j int) bool { if pq[i].priority == pq[j].priority { return pq[i].service < pq[i].service } return pq[i].priority > pq[j].priority } func (pq PriorityQueue) Swap(i, j int) { pq[i], pq[j] = pq[j], pq[i] pq[i].index = i pq[j].index = j } func (pq *PriorityQueue) Push(x interface{}) { n := len(*pq) item := x.(*Item) item.index = n *pq = append(*pq, item) } //優先隊列的Pop並不是用這個Pop,最后的元素並不是優先級最高的! func (pq *PriorityQueue) Pop() interface{} { old := *pq n := len(old) item := old[n-1] item.index = -1 *pq = old[0 : n-1] return item } func (pq *PriorityQueue) Top() *Item { item := heap.Pop(pq).(*Item) heap.Push(pq, item) return item } func (pq *PriorityQueue) update(item *Item, priority, service int, state string) { item.priority = priority item.service = service item.state = state heap.Fix(pq, item.index) } //創建優先隊列 var pq = make(PriorityQueue, 0) func main() { f, err := os.OpenFile("1.txt", os.O_RDONLY, 0777) if err != nil { fmt.Println("沒有找到1.txt!") os.Exit(1) } fmt.Println("請輸入每秒改變優先級n") n := 1 fmt.Scan(&n) reader := bufio.NewReader(f) for i := 0; i < 5; i++ { //每次讀取一行 buf, _, _ := reader.ReadLine() sli := strings.Fields(string(buf)) priint, _ := strconv.Atoi(sli[3]) arrint, _ := strconv.Atoi(sli[1]) serint, _ := strconv.Atoi(sli[2]) //創建實例 one := &Item{ name: sli[0], priority: priint, index: i, arrival: arrint, service: serint, oldservice: serint, state: sli[4], } heap.Push(&pq, one) } //初始化堆 heap.Init(&pq) fmt.Println("請輸入第x秒后的狀態:") x := 0 fmt.Scan(&x) //執行, 初始總數n為5,x為循環次數 num := 5 for second := 1; second <= x; second++ { time.Sleep(time.Second) // pq[num] != heap.Pop(*pq)!!! //臨時優先隊列 var tempq = make(PriorityQueue, 0) //遍歷所有堆元素,僅pq[0]優先級最高! for i := 0; i < num; i++ { onepq := pq[i] if onepq.state == "F" { //添加到tempq tempq = append(tempq, onepq) continue } //服務時間不為0,就讓其-1,state設為R if onepq.service != 0 { if i == 0 { //優先級最高 onepq.priority = pq[i].priority - n onepq.service = pq[i].service - 1 onepq.state = "R" } else { //堆里其他元素 onepq.priority = pq[i].priority + n onepq.state = "W" } } else { //service=0, state設為F onepq.state = "F" } //添加到tempq tempq = append(tempq, onepq) } //刪除堆里所有元素 for pq.Len() > 0 { heap.Pop(&pq) } //把所有元素加到堆里 for _, v := range tempq { heap.Push(&pq, v) } //輸出 fmt.Printf("\n第%d秒的狀態表示\n", second) fmt.Println("進程名 | 服務時間 | 目前優先級 | 進程狀態 | 平均周轉時間") //輸出堆 for i := 0; i < num; i++ { if pq[i].oldservice == pq[i].service { fmt.Printf("%v %v %v %v 0\n", pq[i].name, pq[i].service, pq[i].priority, pq[i].state) } else { fmt.Printf("%v %v %v %v %v\n", pq[i].name, pq[i].service, pq[i].priority, pq[i].state, (second-pq[i].arrival)*1.0/(pq[i].oldservice-pq[i].service)) } } } } /* 使用了golang的container/heap包,需要手動實現less/len/swap/push/pop方法,這里也自定義了update和top方法,需要注意有以下幾點: 1. heap並不是按優先級排序的,所以不能用for遍歷,僅pq[0]優先級最高 2. 在遍歷堆內所有節點時不能直接update,因為fix方法會重新構建堆,我這里使用的方式是用切片來保存堆中所有的元素,空堆后再一次性push */
實驗截圖
前4秒狀態:
后2秒狀態: