操作系统课程设计之页面置换算法(流程模拟)
請求分頁系統設計及應用
1. 概述
1.1目的與意義
本次課程設計的目的在于通過實踐進一步扎實頁面置換過程的理論知識、提高實踐動手能力,提高對頁面置換算法的具體過程,數據的流動路線,線程的同步互斥機制的認識程度,提高軟件開發動手能力,熟練掌握從需求到總體設計到詳細設計再到實際運行測試的軟件設計過程。
操作系統的課程設計對我們學習軟件工程專業的同學來說十分重要且必要,可以讓我們通過編程實驗,更加深入得理解和掌握操作系統的基本理論和功能技術,通過這次課設,可以幫助我們將相對抽象的理論應用于實踐,提高分析問題和解決問題的能力,提高編寫和開發系統程序的能力以及交流互助的能力。
1.2主要完成的任務
基本任務:
(1)完成訪問快表、訪問頁表、缺頁中斷、頁面置換等過程的模擬;
(2)完成物理地址的轉換;
(3)完成自動生成邏輯頁面地址,并根據頁面地址獲取邏輯頁面號;
(4)完成頁面地址范圍、訪問地址序列個數、快表訪問時間、頁表訪問時間、缺頁中斷時間、是否訪問快表等參數的設置;
(5)完成線程模擬訪問頁面序列的情況下線程的暫停、終止與恢復功能;
(6)完成FIFO、LRU、LFU、OPT頁面置換算法的實現與模擬;
擴展功能:
(1)完成不同算法在同一頁面訪問序列的情況下缺頁率的對比;
(2)完成同一算法在不同物理塊下缺頁率的對比;
(3)完成FIFO算法Belady現象的驗證;
(4)完成同一算法在不同頁面范圍的下缺頁率的對比(其他變量保持不變);
(5)完成用戶手動分配物理塊的模擬(對某一置換算法,暫停其該線程對頁面序列的訪問,由用戶分配物理塊來擴展該線程的駐留集);
(6)完成CLOCK、PBA頁面置換算法的實現與模擬;
(7)完成創新功能(多個線程使用類似于PBA算法的方法通過獲取互斥空閑物#理塊資源的途徑實現頁面訪問)的實現于模擬;
1.3使用的開發工具
語言及程序:C#
開發平臺:VS2017
運行環境:Windows10
處理器:Intel? Core?i7-7700HQ CPU @2.80GHZ
已安裝的內存(RAM):8.00GB
系統類型:64位操作系統,基于x64的處理器
1.4解決的主要問題
前端:
GDI+的雙緩沖問題
動畫流暢度的提升
用GDI+畫大圖時速度較慢
動畫演示時,拖動滾動條,圖像丟失的問題
用GDI+繪制表格控件的制作(采用特殊圖形作為單元格)。
后端:
解決了最初訪問快表、訪問頁表等過程單獨設計并滿足整體的流程的難題;將成功訪問到某個頁面時對一些數據結構的維護與頁面置換時對一些數據結構的維護分成單獨的函數,并用專門的維護與頁面置換的控制函數來控制,解決了在同一個訪問流程(即先頁面數組越界判斷、快表與頁表的訪問,若頁表中不存在頁面號則缺頁中斷的過程)下,支持不同算法的運行問題;解決了FIFO、LRU、LFU、OPT、CLOCK,頁面置換在相應數據結構設計以及相關數據結構維護上的難題;
2. 使用的基本概念和原理
2.1虛擬存儲器的相關知識
2.1.1對換
(1)將阻塞進程,暫時不用的程序,數據換出
(2)將具備運行條件的進程換入
(3)類型
①整體對換:進程對換,解決內存緊張
②部分對換:頁面對換/分段對換:提供虛存支持
(4)對換空間的管理
外存對換區比文件區側重于對換速度,因此,對換區一般采用連續分配,采用數據結構和分配回收類似于可變化分區分配
(5)換出
①選出被換出進程:
因素:優先級,駐留時間,進程狀態
②換出過程:
對于共享段:計數減1, 是0則換出,否則不換
修改PCB和MCB(或內存分配表)
(6)換入
①選擇換入進程:優先級,換出時間等
②請內存換入
2.1.2地址變換機構
基本任務:邏輯地址——物理地址的映射
(1)頁號→塊號:通過頁表來完成
(2)頁內地址→塊內地址:無需轉換
基本地址變換機構:
(1)越界保護
(2)每個進程對應一頁表,其信息放在PCB中,執行時將其首地址裝入頁表寄存器
(3)地址變化過程
2.1.3多級頁表
?頁表可能很大,將其離散存放在不同頁塊中。
?建一“外部頁表”來管理這些離散頁表塊。
相當于單級頁表中的頁表寄存器,一般應常駐內存。
每項記錄頁表始址,且增加存在位。
?64位機器頁表一般>3級,最外層頁表常駐。
2.1.4尋址技術
物理地址,CPU地址總線傳來的地址,由硬件電路控制(現在這些硬件是可編程的了)其具體含義。物理地址中很大一部分是留給內存條中的內存的,但也常被映射到其他存儲器上(如顯存、BIOS等)。在沒有使用虛擬存儲器的機器上,虛擬地址被直接送到內存總線上,使具有相同地址的物理存儲器被讀寫;而在使用了虛擬存儲器的情況下,虛擬地址不是被直接送到內存地址總線上,而是送到存儲器管理單元MMU,把虛擬地址映射為物理地址。
線性地址(Linear Address)也叫虛擬地址(virtual address)是邏輯地址到物理地址變換之間的中間層。在分段部件中邏輯地址是段中的偏移地址,然后加上基地址就是線性地址。是一個32位無符號整數,可以用來表示高達4GB的地址,也就是,高達4294967296個內存單元。線性地址通常用十六進制數字表示,值得范圍從0x00000000到0xfffffff)程序代碼會產生邏輯地址,通過邏輯地址變換就可以生成一個線性地址。如果啟用了分頁機制,那么線性地址可以再經過變換以產生一個物理地址。如果沒有啟用分頁機制,那么線性地址直接就是物理地址。
邏輯地址是在有地址變換功能的計算機中,訪內指令給出的地址 (操作數) 叫邏輯地址,也叫相對地址,也就是是機器語言指令中,用來指定一個操作數或是一條指令的地址。要經過尋址方式的計算或變換才得到內存儲器中的實際有效地址即物理地址。一個邏輯地址由兩部份組成,段標識符: 段內偏移量。段標識符是由一個16位長的字段組成,稱為段選擇符。其中前13位是個索引號,后面3位包含一些硬件細節。
2.1.5交換技術
缺頁異常被觸發通常有兩種情況——
(1)程序設計的不當導致訪問了非法的地址
(2)訪問的地址是合法的,但是該地址還未分配物理頁框
2.1.6內存管理技術
堆和棧都是虛擬地址空間上的概念
2.1.7段頁安全思想
基本思想:
分頁系統能有效地提高內存的利用率,而分段系統能反映程序的邏輯結構,便于段的共享與保護,將分頁與分段兩種存儲方式結合起來,就形成了段頁式存儲管理方式。
在段頁式存儲管理系統中,作業的地址空間首先被分成若干個邏輯分段,每段都有自己的段號,然后再將每段分成若干個大小相等的頁。對于主存空間也分成大小相等的頁,主存的分配以頁為單位。
段頁式系統中,作業的地址結構包含三部分的內容:段號,頁號,頁內位移量。
程序員按照分段系統的地址結構將地址分為段號與段內位移量,地址變換機構將段內位移量分解為頁號和頁內位移量。
為實現段頁式存儲管理,系統應為每個進程設置一個段表,包括每段的段號,該段的頁表始址和頁表長度。每個段有自己的頁表,記錄段中的每一頁的頁號和存放在主存中的物理塊號。
2.2 內存分配策略
在請求分頁系統中,可采取兩種內存分配策略,即固定和可變分配策略。在進行置換時,也可采取兩種策略,即全局置換和局部置換。
(1)固定分配局部置換
(2)可變分配全局置換
(3)可變分配局部置換
2. 3頁面置換算法
把選擇換出頁面的算法稱為頁面置換算法置換算法的好壞將直接影響到系統的性能。
本實驗小組完成的頁面置換算法由FIFO、LRU、LFU、OPT、改進CLOCK下面將詳細介紹上述算法中涉及到的思路以及需要的設計結構等問題。
(1)FIFO算法
思路:選擇在內存駐留時間最長的頁面進行置換
實現:維護一個記錄所有位于內存中的邏輯頁面鏈表,鏈表元素按駐留內存的時間排序,鏈首最長,鏈尾最短,出現缺頁時,選擇鏈首頁面進行置換,新頁面加到鏈尾
特點:實現簡單;性能較差,調出的頁面可能是經常訪問的
該算法通過一個先進先出隊列實現對置換哪個駐留集中頁面的選擇的問題。但是該算法隨著分配的物理塊增大,有時會出現缺頁率上升的現象,即Belady現象,繪制FIFO隨著物理塊數增大缺頁率的變化情況以及設定好特殊的頁面訪問序列成功的實現了FIFO算法的Belady現象的觀察。
頁面置換算法的功能:當出現缺頁異常,需調入新頁面而內存已滿時,置換算法選擇被置換的物理頁面。
(2)LRU算法
思路:選擇最長時間沒有被引用的頁面進行置換,因為如果某些頁面長時間未被訪問,則它們在將來還可能會長時間不會訪問
實現:缺頁時,計算內存中每個邏輯頁面的上一次訪問時間,選擇上一次使用到當前時間最長的頁面
特點:可能達到最優的效果,維護這樣的訪問鏈表開銷比較大
LRU置換算法選擇最近最久未使用的頁面予以淘汰。在本實驗的過程中,小組將LRU算法分成了缺頁時頁面置換以及訪問到頁面時對數據結構的維護兩部分。其中數據結構采用與FIFO相同的隊列,頁面置換部分也保持與FIFO相同,但是在訪問到某一頁面時,通過把隊列中該頁取出放置到隊尾來實現最近最久未使用的頁面永遠放在隊首的方法,好比在模擬一個棧,來實現LRU數據結構的維護。
(3)LFU算法
思路:缺頁時,置換訪問次數最少的頁面
實現:每個頁面設置一個訪問計數,訪問頁面時,訪問計數加1,缺頁時,置換計數最小的頁面
特點:算法開銷大,開始時頻繁使用,但以后不使用的頁面很難置換
在采用LFU算法時,應為在內存中的每個頁面設置一個移位寄存器,用來記錄該頁面被訪問的頻率。該置換算法選擇在最近時期使用最少的頁面作為淘汰頁。
將LFU實現簡化為統計之前訪問頁面的次數,訪問次數最少的頁面將會被新訪問的頁面置換出去。
(4)OPT算法
其所選擇的被淘汰頁面將是以后永不使用的,或許是在最長(未來)時間內不再被訪問的頁面。采用最佳置換算法通??杀WC獲得最低的缺頁率。
OPT算法在實際中不可能實現,但是在模擬的過程中,知道以后會訪問什么頁面是已知的,所以讓OPT算法的模擬實現成為可能。
在OPT算法中并沒有用到特定的數據結構,僅通過獲取接下來的訪問頁面的序列便可以實現對將來最久未使用的頁面的確定。
(5)CLOCK算法
2.4 進程與線程
進程是操作系統資源分配的基本單位,而線程是任務調度和執行的基本單位。
為模擬虛擬存儲器中的不斷訪問頁面的進程,實驗過程中使用多個線程的并發執行來模擬虛擬存儲系統當中的進程。在之后的描述中也會用進程來描述小組模擬的實際過程,但請明確這些“進程”實際上是通過線程來實現的。
進程的執行過程是線狀的, 盡管中間會發生中斷或暫停,但該進程所擁有的資源只為該線狀執行過程服務。一旦發生進程上下文切換,這些資源都是要被保護起來的。這是進程宏觀上的執行過 程。而進程又可有單線程進程與多線程進程兩種。我們知道,進程有 一個進程控制塊 PCB ,相關程序段 和 該程序段對其進行操作的數據結構集 這三部分,單線程進程的執行過程在宏觀上是線性的,微觀上也只有單一的執行過程;而多線程進程在宏觀上的執行過程同樣為線性的,但微觀上卻可以有多個執行 操作(線程),如不同代碼片段以及相關的數據結構集。線程的改變只代表了 CPU 執行過程的改變,而沒有發生進程所擁有的資源變化。除了 CPU 之外,計算機內的軟硬件資源的分配與線程無關,線程只能共享它所屬進程的資源。與進程控制表和 PCB 相似,每個線程也有自己的線程控制表 TCB ,而這個 TCB 中所保存的線程狀態信息則要比 PCB 表少得多,這些信息主要是相關指針用堆棧(系統棧和用戶棧),寄存器中的狀態數據。進程擁有一個完整的虛擬地址空間,不依賴于線程而獨立存在;反之,線程是進程的一部分,沒有自己的地址空間,與進程內的其他線程一起共享分配給該進程的所有資源。
資源互斥
在使用GDI+進行畫圖時,因為要同時運行多個線程,而所有的線程都會公用一個畫圖的緩沖區,所以要進行資源互斥的設計,同時對每個方法中使用的公共變量可以采用生成對應的局部變量,或者是使用mutex進行限制。
3. 總體設計
3.1 技術總路線
本次課設的前端(展示)及后端(算法處理、接口等)的基本技術路線均是先面向過程寫方法,然后采用面向對象的方法進行封裝。(1)采用快速原型的方法,先實現前端界面的主要功能的大致顯示。
(2)然后對后臺進行開發。
(3)前后臺接口設計。
(4)前后臺交互。
(5)前端界面優化
(6)創新點開發
3.2.總體結構
本次課設項目共分為三大部分(1)前端設計
(2)后臺設計
(3)接口設計
主要分為三個大模塊
(1)不同的頁面置換算法的速度和缺頁率的比較如下圖
(2)簡易動畫的制作,對話碰撞模型的構建如下圖
(3)知識遷移,利用(2)中的原理來模擬一個尋仙問路游戲(不完善,不感興趣建議跳過)下圖
3.3 總體實現流程
(1)采用快速原型的方法,簡單的建立了一個前端的面向過程的界面,從而弄清項目中的難點
(2)針對項目中的難點進行后臺開發
(3)采用面向對象的方法進行封裝
(4)進行接口的設計
(5)美化前端
3.4后端主要創立的線程及其任務
(1)動畫運行線程,主要負責動畫的動態運行
(2)加速線程,對動畫的速度進行調整
(3)每個頁面置換都獨立為一個線程
(4)一個線程運行所有的頁面置換算法。
(5)更新數據線程,主要負責跟隨動畫的運行實時更新數據。
(6)一個線程負責準備GDI+繪制圖片
(7)各種監視其他線程執行情況的線程
3.6 數據保存與展示的設計
數據保存:
(1)保存輸入的數據和運行結果
(2)保存運行截圖
數據展示:
(1)直觀的以表格的形式來并發或者單個執行頁面置換算法。
(2)采用動畫的形式直觀的對數據在CPU,內存,外存之間的數據流動(如下圖)
4. 詳細設計
4.1 頁面參數設計
為方便前端后端的交互、傳輸信息的確定是一個非常重要的工作。頁面參數既應該滿足在后端實現的過程中可以通過輸入參數來進行算法的執行,也要考慮到前端是否能傳輸這樣的數據。 根據題目要求,添加前端能夠設置頁面邏輯地址的隨機生成、快表訪問時間、頁表訪問時間、缺頁中斷時間等信息。 根據創先內容及后臺需要,還需要對頁面訪問模擬過程中分配的物理塊以及需要頁面訪問的最大值等信息的設計。 根據上述基本需求,可以設定需求的基本參數信息,為了方便對其管理,單獨將其設置為一個頁面請求類Request,其存儲的基本信息參數如下所示: 1.class Request //全局變量設置 2. { 3. public static ArrayList test_FIFO = new ArrayList(); 4. public static ArrayList test_LRU = new ArrayList(); 5. public static ArrayList test_OPT = new ArrayList(); 6. public static ArrayList test_SNRU = new ArrayList(); 7. public static bool kuaibiao = true;//快表的有無 8. public static int NumsOfwulikuai = 3; //頁內物理塊個數 --相當于對快表大小的限制 9. public static int TimeOfneicun = 100; //內存的存取時間 10. public static int TimeOfkuaibiao = 10; //訪問快表時間 11. public static int TimeOfqueye = 500; //缺頁中斷時間 12. // public static int NumsOfneicun = 20; //內存中的數量--頁表的大小 13. public static int NumsOfYebiao = 20; //內存中的數量--頁表的大小 14. public static int NumsOfKuaibiao = 20; //內存中的數量--頁表的大小 15. // public static string xulie = "1323H,3516H,16A7H,6B23H,3D21H,16FCH,7121H,36FCH,9121H"; 16. public static string xulie = "70000H, 00000H, 1AAA0H, 2AAA0H, 0AAA0H, 3AAA0H, 0AAA0H, 4AAA0H,2AAA0H,3AAA0H,0EEE0H, 3AAA0H, 2AAA0H, 1AAA0H, 2AAA0H, 0AAA0H, 1AAA0H, 7AAA0H,0AAA0H,1AAA0H"; 17. public static string[] physicalArray = { "70000H", "00000H", "1AAA0H", "2AAA0H", "0AAA0H", "3AAA0H", "0AAA0H", "4AAA0H", "2AAA0H", "3AAA0H", "0EEE0H", "3AAA0H", "2AAA0H", "1AAA0H", "2AAA0H", "0AAA0H", "1AAA0H", "7AAAH","0AAAH","1AAAH" }; 18. public static string[] logicArray = { "7", "0", "1", "2", "0", "3", "0", "4", "2", "3","0","3","2","1","2","0","1","7","0","1"}; 19. } 將其設置為全局變量,實現多個實例的request訪問的唯一性。人物移動的數據結構設計實現展示如下:
1.
4.2 頁面訪問
處理設計
訪問快表、訪問頁表以及缺頁中斷等操作進行分開封裝,方便進行后期有無頁表,并方便多個頁面置換算法的實現。以為代碼較長,這里只展示一個創新性的改進的SNRU算法。 1.public void SNRU() 2. { 3. init(); 4. Dictionary<int, string> map = new Dictionary<int, string>();//存儲每一個內存頁框所存的內容 5. string outline = ""; 6. int totalVisitTime = 0; 7. int sleepTime = 0; 8. int unFindCount = 0; 9. //初始化 10. for (int i = 0; i < Request.NumsOfwulikuai; i++) 11. { 12. Q[i].pageId = -1; 13. Q[i].A = 0; 14. Q[i].M = 0; 15. } 16. stack1CurrentX = stack1InitialX + 70;//Stack1的初始坐標X+70 17. for (int i = 0; i < xulieLength; i++) //xulieLength表示有多少個要訪問的塊 18. { 19. outline = ""; 20. sleepTime = 0; 21. stack1CurrentY = stack1InitialY;//Stack1的初始坐標Y 22. string currentPage = Request.logicArray[i].Trim();//待處理元素 23. int changedLocation = -1; 24. if (!inblock(currentPage))//缺頁 25. { 26. unFindCount++;//缺頁次數加1 27. if (map.Count() < Request.NumsOfwulikuai) 28. { //物理塊未裝滿 不用置換,直接添加 29. int loaction = map.Count();//頁面的Key,入隊的位置 30. map.Add(loaction, currentPage); 31. for (int k = 0; k < Request.NumsOfwulikuai; k++) 32. { 33. if (Q[k].pageId == -1) 34. { 35. Q[k].pageId = str16_int10(currentPage); 36. break; 37. } 38. } 39. } 40. else 41. { //物理塊已經裝滿,進行頁面置換 42. int loaction = Search(); 43. Q[loaction].pageId = str16_int10(currentPage); 44. Q[loaction].A = 1; 45. changedLocation = loaction; 46. map.Remove(loaction); 47. map.Add(loaction, currentPage); 48. } 49. 50. if (kuaibiao_exist) 51. { 52. totalVisitTime += Request.TimeOfkuaibiao + Request.TimeOfneicun + Request.TimeOfqueye + Request.TimeOfkuaibiao + Request.TimeOfneicun; 53. sleepTime = Request.TimeOfkuaibiao + Request.TimeOfneicun + Request.TimeOfqueye + Request.TimeOfkuaibiao + Request.TimeOfneicun; 54. 55. } 56. else 57. { 58. totalVisitTime += (Request.TimeOfneicun + Request.TimeOfqueye + Request.TimeOfneicun);//訪問內存時間+缺頁中斷時間 59. sleepTime = (Request.TimeOfneicun + Request.TimeOfqueye + Request.TimeOfneicun); 60. } 61. 62. 63. mutexForGraphic.WaitOne(); 64. #region 動態演示,通過圖形更新 65. //繪制當前訪問頁 66. g.DrawRectangle(pen, stack1CurrentX, stack1CurrentY, dx, dy); 67. g.DrawString(currentPage, font, brush, stack1CurrentX + 4, stack1CurrentY + 4); 68. 69. //繪制內存情況 70. foreach (KeyValuePair<int, string> pair in map) 71. { 72. stack1CurrentY += dy; 73. g.DrawRectangle(pen, stack1CurrentX, stack1CurrentY, dx, dy); 74. if (pair.Key == changedLocation) 75. { 76. g.DrawString(pair.Value, font, brushred, stack1CurrentX + 4, stack1CurrentY + 4); 77. } 78. else 79. { 80. g.DrawString(pair.Value, font, brush, stack1CurrentX + 4, stack1CurrentY + 4); 81. } 82. } 83. for (int j = 0; j < (Request.NumsOfwulikuai - map.Count()); j++) 84. { 85. stack1CurrentY += dy; 86. g.DrawRectangle(pen, stack1CurrentX, stack1CurrentY, dx, dy); 87. g.DrawString("", font, brush, stack1CurrentX + 4, stack1CurrentY + 4); 88. } 89. 90. //是否缺頁 91. stack1CurrentY += dy; 92. g.DrawRectangle(pen, stack1CurrentX, stack1CurrentY, dx, dy); 93. g.DrawString("√", font, brush, stack1CurrentX + 4, stack1CurrentY + 4); 94. 95. //缺頁次數 96. stack1CurrentY += dy; 97. g.DrawRectangle(pen, stack1CurrentX, stack1CurrentY, dx, dy); 98. g.DrawString(unFindCount.ToString(), font, brush, stack1CurrentX + 4, stack1CurrentY + 4); 99. 100. stack1CurrentX += dx; 101. #endregion 102. mutexForGraphic.ReleaseMutex(); //畫布緩沖區 103. } 104. else 105. { 106. 107. if (kuaibiao_exist) //物理塊中有表示快表中也有 108. { 109. totalVisitTime += Request.TimeOfkuaibiao + Request.TimeOfneicun; 110. sleepTime = Request.TimeOfkuaibiao + Request.TimeOfneicun; 111. } 112. else 113. { 114. totalVisitTime += 2 * Request.TimeOfneicun; 115. sleepTime = 2 * Request.TimeOfneicun; 116. } 117. 118. mutexForGraphic.WaitOne(); 119. #region 動態演示,通過圖形更新 120. //繪制當前訪問頁 121. g.DrawRectangle(pen, stack1CurrentX, stack1CurrentY, dx, dy); 122. g.DrawString(currentPage, font, brush, stack1CurrentX + 4, stack1CurrentY + 4); 123. 124. //繪制內存情況 125. for (int j = 0; j < Request.NumsOfwulikuai; j++) 126. { 127. stack1CurrentY += dy; 128. g.DrawRectangle(pen, stack1CurrentX, stack1CurrentY, dx, dy); 129. g.DrawString(" ", font, brush, stack1CurrentX + 4, stack1CurrentY + 4); 130. } 131. //缺頁率情況 132. stack1CurrentY += dy; 133. g.DrawRectangle(pen, stack1CurrentX, stack1CurrentY, dx, dy); 134. g.DrawString(" ", font, brush, stack1CurrentX + 4, stack1CurrentY + 4); 135. 136. //缺頁次數 137. stack1CurrentY += dy; 138. g.DrawRectangle(pen, stack1CurrentX, stack1CurrentY, dx, dy); 139. g.DrawString(unFindCount.ToString(), font, brush, stack1CurrentX + 4, stack1CurrentY + 4); 140. 141. stack1CurrentX += dx; 142. #endregion 143. mutexForGraphic.ReleaseMutex(); 144. } 145. //實時顯示當前最新界面的物理地址 146. MyForm.BeginInvoke(new Action(() => 147. { 148. string text; 149. int tmp = -1; 150. foreach (KeyValuePair<int, string> kvp in map) 151. { 152. if (kvp.Value == currentPage) 153. { 154. tmp = kvp.Key; 155. break; 156. } 157. 158. } 159. if (tmp == -1) 160. { 161. text = "程序未運行"; 162. } 163. string address = Request.physicalArray[i]; 164. address = get_physical_address(tmp, address); 165. text = "當前的最新邏輯頁的物理地址為:" + address; 166. physical_address.Text = text; 167. 168. })); 169. //實時統計缺頁率和累計用時 170. MyForm.BeginInvoke(new Action(() => 171. { 172. double current_queyelv = ((unFindCount * 1.0 / (i + 1)) * 100); 173. Request.test_SNRU.Add(current_queyelv); 174. quyelv.Text = "改進的CLOCK算法當前缺頁率:" + unFindCount + "/" + (i + 1) + "=" + ((unFindCount * 1.0 / (i + 1)) * 100).ToString("F2") + "%"; 175. })); 176. 177. MyForm.BeginInvoke(new Action(() => 178. { 179. totaltime.Text = "改進的CLOCK算法當前累計用時:" + totalVisitTime + "nm"; 180. })); 181. 182. 183. System.Threading.Thread.Sleep(sleepTime); 184. } 185. mutexForGraphic.WaitOne(); 186. #region 統計信息 187. stack1CurrentY = stack1InitialY; 188. g.DrawString("統計信息", font, brush, stack1CurrentX + 4, stack1CurrentY + 4); 189. stack1CurrentY += dy; 190. g.DrawString("缺頁率:" + unFindCount + "/" + xulieLength + "=" + (unFindCount * 1.0 / xulieLength) * 100 + "%", font, brush, stack1CurrentX + 4, stack1CurrentY + 4); 191. stack1CurrentY += dy; 192. g.DrawString("累計用時:" + totalVisitTime + "ns", font, brush, stack1CurrentX + 4, stack1CurrentY + 4); 193. #endregion 194. mutexForGraphic.ReleaseMutex(); 195. }對應的流程圖如下
圖16 流程圖4.4 LRU頁面置換設計
LRU采用的數據結構與FIFO數據結構相同,均為一個簡單的Python列表形式。這里我們維護這個列表,保證列表的首部為最久未使用的頁面,列表的尾部為剛訪問的頁面。所以在頁面置換的過程中,我們依舊只需調換隊首元素完成調頁,所以可以發現LRU的實現過程與FIFO是相同的,所以在FIFO中FIFO的調頁函數也適用于LRU。 既然LRU調頁與FIFO一樣,但是顯然二者的算法流程是不一樣的,而且LRU應當是訪問到頁面以后再將頁面放入隊尾更加合適,而不是簡單的置換頁面的時候就把頁面號放入隊尾,因為缺頁調換時并沒有成功獲取到頁面號對應的物理塊號。 為解決上述問題,專門聲明定義了LRU專用數據結構(即self.__access_history列表)的維護函數(當然在其他的算法中也會存在這樣的維護操作): 上述代碼中僅進行了兩個操作,將訪問到的頁面從隊列中彈出來以及將訪問到的頁面放入隊尾。該函數在訪問快表或頁表并成功找到對應頁面號時執行,也就意味著LRU不同于FIFO的地方便是如果頁面號存在于快表或頁表中,則將該頁面號放入隊尾表示該頁面剛剛訪問過。如此便實現了將最近最久未使用的頁面保持在隊列首的位置。4.5 LFU 頁面置換設計
LFU頁面置算法實際上是統計存在于駐留集物理塊中頁面的訪問次數,每次調頁時調換訪問次數最小的頁面調換,如果調換次數最小的頁面有多個頁,則根據一定的邏輯,調換最久未訪問的頁面,設計維護LFU的頁面訪問記錄用的數據結構如下:5. 編碼設計
5.1開發環境的設置和建立
語言及程序:C#
開發平臺:VS2017
運行環境:Windows10
處理器:Intel? Core?i7-7700HQ CPU @2.80GHZ
已安裝的內存(RAM):8.00GB
系統類型:64位操作系統,基于x64的處理器
5.2程序設計時要注意的事項
(1)采用面向對象的方法進行開發
(2)先采用面向過程的方法進行簡易程序的制作
(3)頁面的布局很重要
5.3關鍵構件/插件的特點和使用
本程序都是用VS2017采用C#進行開發,并自己編寫了碰撞模型。
5.4解決的技術難點、經常犯的錯誤
人物移動,碰撞,對話模型的設計與編碼
1.采用一個線程進行監聽(類似TS鎖),物體的
相對位置,滿足條件觸發相應的事件。適用于頻繁互動的情況
2.不頻繁的互動,直接在程序中寫好
線程監聽
基于TS鎖的原理實現,每經過一段時間查看一下被監聽線程的狀態
LFU算法的實現過程中,對于數據結構的設計以及維護非常存在困難,另外LFU表維護的過程中為了保證訪問次數按順序排序,需要有序的插入元素,然而每一個元素并不是簡單的數據結構,在排序過程中存在很多困難。
對創新功能的設計存在一系列的問題:在最初的過程中設定完全按照PBA算法的描述設計,但是由于模擬的空閑物理塊有限,導致如果保留物理塊內數據然后放入空閑物理塊鏈尾,會存在空閑物理塊鏈尾的物理塊被別的進程獲取而導致即使當前進程在第二個時鐘周期有需要該頁面,但存儲該頁面的物理塊已分配給別的進程而導致缺頁率依舊很高的現象,當然經過討論后已經解決了此問題(參考詳細設計)。
6.測試時出現過的問題及其解決方法
遇到的問題:畫面閃爍問題
解決方法:雙緩沖技術
6.1 導致畫面閃爍的關鍵原因分析:
6.1.1繪制窗口由于大小位置狀態改變進行重繪操作時
繪圖窗口內容或大小每改變一次,都要調用Paint事件進行重繪操作,該操作會使畫面重新刷新一次以維持窗口正常顯示。刷新過程中會導致所有圖元重新繪制,
而各個圖元的重繪操作并不會導致Paint事件發生,因此窗口的每一次刷新只會調用Paint事件一次。窗口刷新一次的過程中,每一個圖元的重繪都會立即顯示到窗口,
因此整個窗口中,只要是圖元所在的位置,都在刷新,而刷新的時間是有差別的,閃爍現象自然會出現。
所以說,此時導致窗口閃爍現象的關鍵因素并不在于Paint事件調用的次數多少,而在于各個圖元的重繪。
根據以上分析可知,當圖數目不多時,窗口刷新的位置也不多,窗口閃爍效果并不嚴重;當圖元數目較多時,繪圖窗口進行重繪的圖元數量增加,繪圖窗口每一次刷新
都會導致較多的圖元重新繪制,窗口的較多位置都在刷新,閃爍現象自然就會越來越嚴重。特別是圖元比較大繪制時間比較長時,閃爍問題會更加嚴重,因為時間延遲會更長。
解決上述問題的關鍵在于:窗口刷新一次的過程中,讓所有圖元同時顯示到窗口。
6.1.2進行鼠標跟蹤繪制操作或者對圖元進行變形操作時
當進行鼠標跟蹤繪制操作或者對圖元進行變形操作時,Paint事件會頻繁發生,這會使窗口的刷新次數大大增加。雖然窗口刷新一次的過程中所有圖元同時顯示到窗口,但也會有時間延遲,因為此時窗口刷新的時間間隔遠小于圖元每一次顯示到窗口所用的時間。因此閃爍現象并不能完全消除!
所以說,此時導致窗口閃爍現象的關鍵因素在于Paint事件發生的次數多少。
解決此問題的關鍵在于:設置窗體或控件的幾個關鍵屬性。
6.2 雙緩沖的關鍵技術
在編程當中,或多或少會接觸到圖像編程,對于圖像編程來說窗口閃爍是個常見的問題,當窗口有大量的復雜的圖元數據需要重繪,或者擁有自定義控件中的窗口閃爍問題更是顯而易見的。出現閃爍的原因有很多種,大部分原因主要是因為觸發WM_PAINT消息時窗體進行了重繪操作,此過程先是用窗體的背景色擦除窗口表面,再把窗體的圖像繪制上去,但是如果這2個操作不在同一時間段完成的話,就會先看到背景色(大部分為白色)接著才看到圖像,這樣就會出現我們所說的窗體閃爍現象。那么如何解決這個問題呢,解決方法有很多,其中有個比較好的方法(個人認為)就是采用雙緩沖機制來繪圖,基本上可以解決大部分的問題。
雙緩沖的原理:盡量快的輸出圖像,使輸出在一個刷新周期內完成,如果輸出內容很多比較慢,那么采用內存緩沖的方法,先把要輸出的內容在內存準備好,然后一次性輸出到窗體上,簡單的說來就是在窗口刷新一次的過程中,讓所有圖元同時顯示到窗口中。
在C#中 .Net Framework為編程人員提供了很好的操作雙緩沖的方法,為采用雙緩沖機制繪制比較復雜的圖像數據帶來便捷。下面簡單的介紹在C#中實現雙緩沖的幾種方法。
利用默認的雙緩沖
(1)在應用程序中使用雙緩沖的最簡便的方法是使用 .NET Framework 為窗體和控件提供的默認雙緩沖。通過將 DoubleBuffered 屬性設置為 true。
1.this.DoubleBuffered=true;(2)使用 SetStyle 方法可以為 Windows 窗體和所創作的 Windows 控件啟用默認雙緩沖,在窗體或者控件的構造函數中添加如下代碼即可:
1. SetStyle(ControlStyles.ResizeRedraw,true); 2. SetStyle(ControlStyles.OptimizedDoubleBuffer,true); 3. SetStyle(ControlStyles.AllPaintingInWmPaint,true); 4.或者: 1. this.SetStyle(ControlStyles.ResizeRedraw | 2. ControlStyles.OptimizedDoubleBuffer | 3. ControlStyles.AllPaintingInWmPaint, true); 4. this.UpdateStyles(); 在C# 中手動管理緩沖圖像有2中方法,一種是利用單獨開辟內存實現雙緩沖這種傳統的方法,還有一種是利用 .Net Framework 中獨有的BufferedGraphicsContext類實現。方法一: 自己開辟一個緩沖區(如一個不顯示的Bitmap對象),在其中繪制完成后,再一次性顯示,代碼如下: 1. //1、在內存中建立一塊“虛擬畫布” 2. Bitmap bmp = new Bitmap(200,200); 3. 4. //2、獲取這塊內存畫布的Graphics引用 5. Graphics bufferGraphics = Graphics.FromImage(bmp); 6. 7. //3、在這塊內存畫布上繪圖 8. bufferGraphics.Clear(this.BackColor); 9. bufferGraphics.DrawRectangle(Pens.Black,0,0,bmp.Width -1,bmp.Height -1); 10. bufferGraphics.DrawEllipse(Pens.Red,10,10,100,50); 11. bufferGraphics.DrawLine(Pens.Green,10,100,100,200); 12. 13. //4、將內存畫布畫到窗口中 14. using(Graphics g = e.Graphics) 15. { 16. g.DrawImage(bmp, 10, 10); 17. } 18. 19. //5. 釋放資源 20. bmp.Dispose(); 21. bufferGraphics.Dispose();7. 軟件使用說明
(1)基本功能
①多個頁面置換算法的比較
②動畫的演示
(2)需要運行的環境 windows10
(3)安裝 exe文件
(4)運行 windows10
(5)操作 直接界面即可
8. 總結
(1)完成的部分
動畫游戲模型搭建完畢,正打算應用于一個自己開發的小游戲。
(2)未完成的部分
小游戲實現了人物的移動,以及自動尋路的過程,正在完善打怪升級的程序。
(3)創新功能
①對CLOCK算法進行了改進,對PBA算法進行挖掘,同時對LFU算法的不同實現過程進行了對比。
②允許多個線程并發執行,對比鮮明。
③制作了較為直觀的動畫展示過程
(4)收獲、經驗、教訓和感受等
收獲:
①自己寫了簡易的碰撞,跟隨,對話模型,對于一些集成開發工具的原理有了一定的簡單了解
②掌握了一定的多線程編程策略
③對數據在cpu,內存,外存之間的運轉有了更深的理解
(5)經驗教訓:
①界面布局很重要
②明確用戶的需求
③項目的開發要及時的進行審查。
(6)感受:
最后,衷心感謝老師的悉心指導,感謝這次課程設計的機會,使我們得到了很好的鍛煉,學無止境,我們現在了解的東西還很少,還不能很好地掌握自己的專業知識,我們要謙虛的積極認真學習,不斷的增強自身的能力,提高個人素質,向一個真正的IT人士發展。
9.參考文獻
[1]博客boobo 頁面置換算法及例題
原文鏈接:https://www.cnblogs.com/RB26DETT/p/10035804.html
[2]博客IuStar 操作系統(5)頁面置換算法
原文鏈接:https://www.cnblogs.com/lustar/p/7875705.html
[3]博客 奄奄不息 頁面置換算法詳解
原文鏈接:https://blog.csdn.net/qq_41209741/article/details/99586257
總結
以上是生活随笔為你收集整理的操作系统课程设计之页面置换算法(流程模拟)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 前端学习(1514):vue-route
- 下一篇: 操作系统课程设计 —— 模拟磁盘文件系统