Nachos操作系统实习-lab1
Nachos操作系統實習-lab1
- 內容一:總體概述
- 內容二:任務完成情況
- 內容三:遇到的困難以及解決方法
- 內容四:收獲及感想
- 內容五:對課程的意見和建議
- 內容六:參考文獻
內容一:總體概述
本次 lab 的主要內容是在理解 Nachos 線程管理機制的基礎上進行擴展,添加 UID 和 TID 兩個成員變量,并增加相應的維護機制;此外,還需要設置 Nachos 允許同時存在的最大線 程數并增加 TS 指令。本次 lab 的重點在于理解 Nachos 的線程管理機制,在理解的基礎上進一步拓展其功能。
內容二:任務完成情況
任務完成列表(Y/N)
| 完成情況 | Y | Y | Y | Y |
具體Exercise的完成情況
Exercise1 調研
Linux中進程控制塊的基本實現方式:
每一個進程由一個對應的task_struct數據結構描述,用來維護進程的相關信息。其中包含有:
(1) 進程狀態。一共有TASK_RUNNING(可運行)、TASK_INTERRUPTIBLE(可中斷的等待狀態)、TASK_UNINTERRUPTIBLE(不可中斷的等待狀態)、TASK_STOPPED(暫停)、TASK_ZOMBIE(僵死)、TASK_SWAPPING(換入/換出)六種狀態。
(2) 進程調度信息。決定系統中哪個進程最應該運行,進程的調度策略分為SCHED_OTHER(其他調度)、SCHED_FIFO(先來先服務調度)、SCHED_RR(時間片輪轉調度)三種。
(3) 標識符(PID)。每個進程由一個唯一的標識符確定,PID是一個32位的無符號整數,被順序編號,用戶程序通過PID調度進程。
(4) 進程通信有關信息(IPC)。管理進程之間數據的交流。
(5) 進程鏈接信息。管理進程之間的父/子關系,使進程之間的協作更加方便。
(6) 時間和定時器信息。記錄進程從創建到終止使用CPU的時間,以便進行統計、計費等有關操作。
(7) 文件系統信息。記錄進程使用文件的情況。
(8) 虛擬內存信息。管理每個進程的地址空間(虛擬空間)。
(9) 頁面管理信息。當物理內存不足時,負責進行頁面的交換。
(10) 和處理器相關的環境信息。當進程暫時停止運行時,處理器必須保存上下文信息在進程的thread_struct結構中,當進程被調度重新運行時再恢復這些環境。
(11) 其他。
與Nachos中進程控制塊的基本實現方式的異同:
Nachos的進程控制塊相關信息定義在code/threads/thread.h中,其中只包含有stackTop指針(指向棧頂)、stack指針(指向棧底)、status(JUST_CREATED, RUNNING, READY, BLOCKED)、name、machineState(保存其他未運行進程寄存器的狀態)。相比較Linux中PCB的實現方式,Nachos中的信息較少,實現較為簡單,只有一些基本的狀態參數和基本的操作函數。
Exercise2 源代碼閱讀
main.cc是Nachos整個程序的入口,其中對整個Nachos中的數據結構進行了初始化,此外解析命令行傳入的參數,根據不同的參數進而調用Nachos的不同方法。
threadtest.cc提供了thread的測試方法,當testnum被設置成1的時候,ThreadTest函數會進一步調用ThreadTest1函數,ThreadTest1函數會創建一個線程,該線程會進一步fork出一個子線程,兩個線程都去調用SimpleThread函數,通過線程的Yield函數自動放棄占用CPU,實現兩個線程交替輸出。
thread.h提供了Thread類的定義,其中包括棧頂指針、棧底指針、線程名字、線程狀態、寄存器狀態等變量,也聲明了Fork()、Yield()、Sleep()、Finish()、CheckOverflow()、setStatus()、getName()、Print()、ThreadAllocate()這些針對線程操作的函數。
thread.cc中對thread類的構造函數、析構函數以及各個成員函數進行了具體化,如Fork()通過分配并初始化堆棧,將一個線程放入準備隊列;CheckOverflow()檢查棧是否溢出;Finish()設置threadToBeDestroyed為當前線程,并調用Sleep()函數;Sleep()將當前線程的狀態設置為BLOCKED,尋找下一個即將運行的線程;Yield()尋找下一個即將運行的線程,通過scheduler->Run()使新的線程占用CPU運行;StackAllocate()為線程分配需要的堆棧空間。其中Fork()、Finish()、Sleep()、Yield()的操作都是原子的,通過interrupt->SetLevel(IntOff)保存中斷層次關閉中斷,在操作完成后再恢復原狀態。
Exercise3 擴展線程的數據結構
第一步:先在thread.h中為Thread類添加了UID和TID兩個int型的變量,然后聲明了get_UID()和get_TID()兩個函數,分別返回該線程的UID和TID。
第二步:在system.cc中定義一個長度為128的int型數組TID_list,用于記錄已經被占用的TID編號,在Initialize()函數內將其初值賦為0。之后在system.h中外部聲明這個數組。
第三步:在thread.cc中為UID和TID兩個成員變量進行維護。首先在構造函數中,對于一個新的線程,調用系統getuid()函數獲得UID編號,順序遍歷TID_list找到第一個沒有被占用的TID編號。接下來在析構函數中,當一個線程被釋放時,將其占用的TID編號恢復空閑,方便之后的線程使用。
Exercise4 增加全局線程管理機制
第一步:如Exercise3中所述,將TID_list的大小設置為128,即Nachos中最多能同時存在128個線程。在thread.cc的構造函數中,當找不到一個空閑的TID編號時,將當前線程的TID編號設為-1,通過ASSERT( TID != -1 )使程序強制終止。
第二步:增加一個TS命令,為了顯示當前系統中所有線程的信息和狀態,需要為每個線程保存一個指向它的指針。于是在system.cc中定義長度為128的指針數組threadPointer,用來指向對應TID編號的線程,同時在system.h中外部聲明該數組。
第三步:在thread.cc中構造函數中,設置新創建線程TID編號對應的指針指向該線程;在析構函數中,讓對應指針指向NULL。
第四步:由于需要打印線程狀態,所以在thread.h中為Thread類添加成員函數get_status(),用來返回當前線程的狀態。
第五步:在threadtest.cc中創建相應的測試函數ThreadTest2()和ThreadTest3(),分別對應testnum為2和3的情況。其中ThreadTest2中創建超過128個線程用來測試最大線程數量;ThreadTest3中打印所有現存線程的name, UID, TID和status。并在main.cc中添加為測試最大線程數量和TS指令設置相應testnum的程序。
最大線程數量測試結果如下:
TS指令測試結果如下:
內容三:遇到的困難以及解決方法
困難1 不知道怎么設置當前線程的UID
一開始我嘗試將所有線程的UID都設置為0,但之后在上網查閱資料的過程中了解到,linux系統中可以通過包含兩個頭文件<unistd.h>和<sys/types.h>進而調用getuid()函數獲得當前UID,問題得到解決。
內容四:收獲及感想
通過完成這次lab,我對Nachos的線程管理機制有了更加深入的理解,同時通過調研linux中進程控制塊的實現,對二者的區別有了更加清晰的認識。
在做lab之前我也調研閱讀了關于Nachos的一些文獻,其中對于Nachos的線程管理機制也有描寫,但是讀書不如親自動手來的效果好,在做完lab之后,才可以說對于書中的描述有了更加深刻的理解。
內容五:對課程的意見和建議
我建議討論課的時候可以大家多交流交流自己lab的實現方式,看看有沒有一些比較好的想法,也可以看看大家有沒有碰到一些相同的問題,可以討論一起解決,一起進步。
關于Nachos源碼的問題我也遇到了一個,就是Nachos中線程第一次運行時不會調用scheduler::run,因此導致不會釋放之前的線程。我在析構函數中添加打印函數后,發現對于test1的結果只有一個線程被回收了。經過群里討論助教說明了是Nachos本身的問題。
內容六:參考文獻
[1] Andrew S. Tanenbaum著.陳向群 馬洪兵 譯 .現代操作系統[M].北京:機械工業出版社,2011:47-95.
[2] linux進程控制塊task_struct描述:
https://blog.csdn.net/jnu_simba/article/details/11724277?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
[3] linux系統編程之進程: https://www.cnblogs.com/mickole/p/3185889.html
總結
以上是生活随笔為你收集整理的Nachos操作系统实习-lab1的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 详解JavaScript中void语句的
- 下一篇: 个人进度(04)