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