生活随笔
收集整理的這篇文章主要介紹了
nachos
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
nachos實驗記錄
- 實驗一
- 分析threads文件夾內容
- thread
- scheduler
- 初始化函數Initialize()的工作
- main()函數的工作
- gdb基本使用
- 實驗三
- 實驗四,五
- 理解nachos的文件系統
- 簡單介紹
- 管理方式
- nachos模擬的文件系統
- 文件操作
- 實驗六
- 實驗七,八
- 總結
實驗一
分析threads文件夾內容
思路:通過thread類中的方法,來調用schedule類中的調度函數,實現線程的創建,就緒,運行,阻塞和結束五種狀態的轉換。
thread
創建線程:fork()。首先為線程分配棧資源(StackAllocate()),然后將線程狀態設為就緒態(setStatus()),并放入就緒隊列中(Append()),等待被調度即可。線程阻塞:sleep()。首先將狀態設置為阻塞態,然后從就緒隊列中尋找新的線程來調度(FindNextToRun()),如果就緒隊列中有線程就可以執行該線程(run()),如果就緒隊列中沒有線程則阻塞等待時鐘中斷到來(idle())。線程切換:yield()。 從就緒隊列中尋找新的線程來調度(FindNextToRun()),如果就緒隊列中有線程就可以執行該線程(run()),同時將當前運行的線程放入就緒隊列中(ReadyToRun());如果就緒隊列中沒有線程,則修改狀態后直接退出即可。(區別于sleep(),yield()不會進入阻塞等待狀態)線程結束:finish()。先將線程標記為待刪除的線程(Run()中進行刪除),然后直接調用sleep()即可。為什么不調用yield():因為yield()雖然也釋放cpu資源,但卻將線程再次放入就緒隊列中,而線程結束則意味著線程不需要再使用cpu,因此不應該再放入就緒隊列中,調用sleep()則正好滿足要求。
scheduler
尋找下一個運行的線程:FindNextToRun()。查看就緒隊列中是否還有線程,如果有就從就緒隊列中刪除這個線程,并將其返回;如果沒有線程則返回NULL。
準備執行線程:ReadyToRun()。本質上就是創建到就緒態的轉換,先將線程狀態設為就緒態(setStatus()),然后將其放入就緒隊列中即可(Append())。執行線程:Run()。本質上就是就緒態到運行態的轉換,先將線程狀態設為運行態(setStatus()),然后進行上下文的切換(SWITCH()),最后判斷被調度下去的線程是否需要銷毀(finish()中進行的設置),如果要銷毀那么就進行destory。
初始化函數Initialize()的工作
這個屬于system類,即當執行一個main()函數時,操作系統自己進行的初始化工作。首先進行硬件資源如磁盤和網絡設備的初始化工作,這里頻繁使用ifdef,endif的搭配組合,工程項目中須要掌握這點。之后進行中斷,調度隊列,時鐘的初始化。然后便可以創建main()主線程,并將其設為運行狀態。
main()函數的工作
注意,這個main()函數并不是我們寫的main()函數,而是nachos操作系統運行的內核程序,因為操作系統本質上也是一個程序,而nachos作為一個模擬的操作系統也自然需要去運行。main()函數首先調用Initialize()函數進行初始化工作,需要關注的是之后調用了ThreadTest()函數做測試,其中又調用了fork()創建了新的線程,并用新的線程和主線程均調用了SimpleThread()函數,但是傳遞的參數卻不同,因此執行結果自然不同。
gdb基本使用
查看函數地址:首先list,然后找到要查看的函數位置,利用break設置斷點即可。查看線程對象地址:首先list,找到創建線程的代碼位置,并利用break在創建線程返回值的位置設置斷點,然后用run命令運行線程,到達這個位置時會暫停,此時利用p查看線程地址即可。查看匯編代碼的返回地址:可以用break在函數入口打斷點,然后利用disass查看匯編代碼,由于函數返回時一定會將返回地址放入寄存器中,則可以在返回的匯編代碼的下一步中,利用info r查看寄存器內容,從而得到返回地址。需要注意的是,s和n命令都是c語言級的,想要單步執行匯編代碼,需要利用si和ni,這些命令是匯編級的。
實驗三
分析synch文件
首先需要了解的是,list文件中自己實現了鏈表節點,并基于此實現了鏈表類,然后在synch文件中利用這個鏈表實現了信號量,互斥鎖和條件變量。其中信號量主要是維護了一個等待當前信號量的線程隊列和信號量的值,而互斥鎖則是維護了一個大小為1的信號量和鎖的擁有者,由于本次實驗我們使用信號量和互斥鎖來實現生產者消費者模型,因此條件變量不在此詳述,只需知道條件變量和互斥鎖配合也完全可以實現生產者消費者模型,這其實可以作為線程池的實現方式。
P()操作:為了實現線程安全,信號量的操作必須是原子性的,而保證原子性的方法就是關掉中斷,即禁止了線程切換。然后判斷當前信號量的值是否為0,若為0則需要加入隊列,并進入阻塞狀態;若不為0則可以將信號量值減一,重新打開中斷即可。V()操作:依然需要先關閉中斷,然后判斷當前隊列中是否有等待的線程,若有則將其從等待隊列中刪除,并準備執行(ReadyToRun())。最后將信號量值加一,并打開中斷。Acquire()操作:首先依然是關閉中斷,然后修改鎖的持有者,并直接調用P()操作即可,最后記得重新打開中斷。Release()操作:首先關閉中斷,然后鎖的持有者設為NULL,并直接調用V()操作即可,最后記得重新打開中斷。
實驗內容
緩沖區是在ring文件中實現的,就是一個簡單的數組,并用in和out標記當前插入和取出的位置。還需要注意的是由于是環形緩沖區,因此需要取余。
需要填充的只有prodcons文件,首先明確的是由于緩沖區是臨界區,因此需要互斥鎖;并且緩沖區的大小有限,不可能無限取,也不可能無限填充,因此需要生產者和消費者進行同步的信號量。因此完成的工作主要是信號量和互斥鎖的初始化,以及生產者的填入數據和消費者的取出數據工作。由于初始時默認緩沖區大小為空,因此對應的取出信號量為0,而填入信號量則為緩沖區大小。此時消費者會進入阻塞狀態,等待生產者填入數據。
當生產者填入數據時首先遵循先同步后互斥的原則,先調用填入信號量的P()操作,然后調用加互斥鎖。然后將數據填入緩沖區中,最后再解鎖和調用取出信號量的V()操作即可。
消費者取出數據道理也類似,先調用取出信號量的P()操作,再加鎖。將數據取出后,再解鎖和調用填入信號量的V()操作即可。
實驗四,五
理解nachos的文件系統
簡單介紹
文件系統是指操作系統層面對磁盤文件的管理。大的層面講就是內部維護文件的管理方式,并向用戶提供對文件進行操作的接口。
例如用戶在使用Linux環境下使用的文件命令:touch,cp,mv,ls,rm…這些都是對Linux中文件進行的操作,其都是通過調用文件的相關操作實現。
在介紹詳細的文件操作過程之前,首先說明一下文件的讀寫和存儲單位,由于磁盤文件的讀寫單位并不是整個文件,而是一個個磁盤塊,文件數據也是按照磁盤塊的單位存放在文件中。因此我們需要管理的最小單位是磁盤塊,而磁盤塊是由一個個扇區組成,一般一個磁盤塊有2^n個扇區,實驗所用的nachos系統中為了簡化,將一個磁盤默認為一個扇區,大小為128B(后面的實驗內容將不再區分磁盤塊和扇區,統一使用磁盤塊表示,但須明白其實這既是磁盤塊,也是扇區)。這樣一個磁盤文件便由多個磁盤塊組成,操作系統負責對所有的磁盤塊進行編址,并進行保存。
既然磁盤文件由多個磁盤塊組成,當我們需要去讀寫某個文件時,就需要去訪問對應的所有磁盤塊,因此需要記錄某個文件所擁有的所有磁盤塊。文件大小,文件所占磁盤塊等信息都統一保存在文件頭中,文件頭也屬于文件,其占據一個磁盤塊。由于文件頭的存在,我們可以從中方便的得知文件的相關信息,但我們如何直到文件頭的位置呢?讀寫文件時如何尋找文件頭呢?這就需要一個根目錄表的結構了,其維護了一個目錄表,表中有多個目錄項,記錄著硬盤中所有文件的名字和文件頭的存放位置。
現在讀寫文件的簡單過程已經梳理好,但是創建和刪除文件的過程還沒有構建。當用戶使用touch命令創建一個文件時,操作系統又是如何操作的呢?
前面說過文件的存儲單位是磁盤塊,那么創建文件時,我們自然需要為創建的文件分配所需的空閑磁盤塊個數 。操作系統如何知道哪些磁盤塊是空閑的呢?nachos中空閑磁盤塊的管理方式是位示圖。其通過位的方式記錄每塊是否已經被分配。這樣當我們需要創建文件時,就查找位示圖,找出所需的塊數,分配即可。
那么回收呢?nachos系統中回收時并不會真的釋放文件內容等,而是將位示圖中文件頭和文件數據對應的磁盤塊標記為空閑,并在目錄表中將對應文件項標記為不再使用,僅此而已。
以上簡單介紹了文件的創建刪除,以及尋找文件的過程。接下來還需要介紹一下文件的復制過程等。
文件的復制過程需要利用上面的幾種操作,比如首先需要得到源文件的大小,然后讀取源文件數據,寫入目標文件中。寫入文件過程較為復雜,需要根據寫入數據的大小,判斷是否需要為目標文件分配新的磁盤塊,這些過程后面將詳細介紹。
大致框架已經搭好,下面將分別詳細介紹上面及部分:
管理方式
位示圖:由于磁盤文件的讀寫單位并不是整個文件,而是一個個磁盤塊,文件數據也是按照磁盤塊的單位存放在文件中。因此需要對空閑的磁盤塊進行管理,這是通過位示圖的方法實現的;位示圖是一個bit數組,其中每bit都代表這一位對應的磁盤塊是否處于空閑狀態。位示圖也有相應的文件頭,并存放在磁盤的第4到第131字節(第0到3字節為nachos硬盤魔數)中,其中記錄了位示圖在第三個磁盤塊中,位示圖文件也占據一個磁盤塊。根目錄表:存放了n條目錄項,每一項通過一個三元組,對一個文件建立了簡單的“索引”,這個三元組由<name, inuse, sector>,分別表示某個文件的名字,以及文件當前是否存在,還有文件頭(下面介紹)所在的扇區號。前面曾經簡單介紹說當刪除一個文件時并不會真正執行文件數據的刪除等操作,那么如何知道該文件是否被刪除呢?就是通過位示圖+目錄項的方式,位示圖比較好理解,而目錄項就是通過inuse來作為標記為進行記錄的,當文件被刪除時,inuse位修改為false即可。
每一個目錄項占20B,該實驗中設定允許存放的最大文件數目為10,因此所需要的大小為200B,必須由兩個磁盤塊來存放。根目錄表的文件頭存放在第二個磁盤塊中,而根目錄表文件存放在第四和第五個磁盤塊中。文件頭:文件頭類似于文件的一個組織者,其記錄了文件的大小,文件所占據的磁盤塊數目,以及用一個數組記錄占據的各個磁盤塊。通過這種方式,當我們需要訪問一個文件時,只需要從根目錄表的文件頭開始,先找到根目錄表所在磁盤塊,并根據name從中讀出所要查找的文件的三元組,三元組的sector部分記錄著所要查找的文件的文件頭所在磁盤塊,然后讀取對應的磁盤塊,獲得文件頭內容,其中記錄著文件數據保存在哪些磁盤塊上,依次讀取即可。
以下是nachos文件系統的簡單布局方式:
nachos模擬的文件系統
由于實驗用的是nachos操作系統,其只是一個簡單的模擬文件系統,并沒有實現真正的硬盤等,因此在介紹一些文件的具體操作之前需要了解一下用磁盤模擬硬盤的方法,方便之后的代碼理解。
我們前面已經介紹了nachos系統的文件管理方式,那么我們如何模擬硬盤呢?實驗中采用的是在一個磁盤文件中模擬,既然是在文件中,那么就涉及到文件的讀寫過程,事實上無論是對文件的任何處理,我們都需要先將文件中保存的目錄表和位示圖從文件中讀出來,并用根目錄表和位示圖這兩個類進行保存,后面對相應數據進行修改,最后寫回文件,也就是虛擬的硬盤中。
文件操作
create:文件的操作中最早的往往是文件的創建工作,因為創建后才能進行后續的相關處理。創建時我們需要首先將保存在虛擬硬盤上的根目錄表和位示圖讀出,判斷目錄表中是否已經存在對應文件名,如果存在則創建失敗;如果不存在,則從位示圖中尋找一個空閑磁盤塊進行分配,用來保存文件的文件頭。如果沒有空閑塊,創建失敗;否則,創建成功,并修改位示圖對應位,以及在根目錄表中插入一個目錄項,并執行文件頭的初始化操作,如文件大小和磁盤塊數等。最后需要將文件頭,根目錄表和位示圖寫回虛擬硬盤中。copy:復制文件的過程實驗中已經提供,首先需要根據源文件的大小,創建一個新的nachos文件;然后循環讀出源文件的數據,并寫入nachos文件中,因為文件大小是已知的,因此我們可以直接進行磁盤塊的分配。然后依次寫入磁盤塊中,并將相應的位示圖和根目錄表進行修改。至于寫入磁盤塊的具體操作,下面會詳細講解。write:寫入文件之前,我們需要首先找到文件的文件頭,這個過程之前已經詳細介紹過,從文件頭中可以得知當前文件的總大小,以及磁盤塊,從而計算出最后一個磁盤塊所使用的空間,然后根據我們要寫入的數據,判斷是否需要分配新的磁盤塊。如果需要,那么讀入位示圖,并調用相關函數,尋找一塊新的空閑磁盤塊進行分配,若沒有空閑磁盤塊返回錯誤即可。若成功分配,那么還需要修改文件的文件頭。獲得足夠的磁盤塊后,需要將當前的數據依次寫入磁盤塊中,由于我們對文件讀寫的最小單位是磁盤塊,因此文件是存在內碎片問題的,即磁盤塊中可能并沒有完全被文件數據占滿空間。因此我們還需要判斷當前磁盤塊是否對齊,如果沒有對齊,需要先讀出最后一塊磁盤塊,然后在此磁盤塊后面進行追加式的寫入。最后需要將文件內容完全寫回硬盤中。remove:文件的刪除操作實際上前面已經簡單介紹過了。首先依然需要將位示圖和根目錄表讀出,nachos系統中回收時并不會真的釋放文件內容等,而是將位示圖中文件頭和文件數據對應的磁盤塊標記為空閑,并在根目錄表中將對應的目錄項的inuse字段標記為false。最后需要將位示圖和根目錄表寫回虛擬硬盤中即可。
實驗六
nachos可執行文件
由于nachos是一個操作系統,因此其運行的可執行文件也是nachos系統下支持的特定文件,其后綴為.noff。分析noff.h文件,可發現其文件內容按照段式存儲,主要由code段,initData段,uninitData段,除此之外還有標識noff文件的魔數。那么段又是由什么構成的呢?首先思考段的構成中必須包含該段數據的內存地址,還有一個就是由于段和頁存儲特點不同,頁式存儲中每頁的大小是固定不變的,而段式存儲是根據段的具體含義,大小可自由定義,因此還需要記錄段的大小。這樣分析之后,段的數據結構呼之欲出:虛擬地址空間中的地址virtualAddr,以及段數據在對應文件中的位置inFileAddr,還有段的大小size。
進程的創建和執行過程
提到進程的創建和執行,Linux系統下首先想到的方法是先使用fork()調用創建子進程,然后通過exec()調用執行對應的可執行文件。nachos系統中也是同理,但這里我們主要討論的是根據文件名進行主進程的創建和執行(還有另一個原因是此時nachos系統還不支持多道程序設計,因此無法支持多進程模式,只能存在一個進程。實驗7,8中將對此進行改進)。
接下來將從userprog/proggtest.cc文件中的StartProcess()函數開始,對nachos系統中進程的創建和執行過程進行詳細的分析:
從大的層面來總結,首先需要根據可執行文件的名稱,打開文件;之后根據文件大小創建用戶地址空間,并初始化頁表內容;然后讀入對應的段數據放入用戶地址空間;用戶地址空間創建之后,本來應該需要創建對應的進程塊,其中保存進程的標識,文件描述符等信息,但是由于此時nachos系統并沒有涉及到多進程,因此也沒有維護進程塊的數據結構,而是將地址空間,頁表等信息由各自的類維護。既然不維護特定的進程塊,那么就需要將系統當前的用戶地址空間切換為對應進程的地址空間,并初始化當前的寄存器,需要注意的是每個進程的地址從0開始,因此PC寄存器的首個存儲內容一定為0;同時修改頁表指針,使其指向當前的進程。這樣便進行了一個簡單的進程創建過程,然后便可以調用Run()函數執行進程。
open():根據文件名打開文件,直接通過nachos文件系統中實現的open()函數即可實現。AddrSpace():用戶地址空間的構造函數,而用戶地址空間的類AddrSpace其實只是維護了一個頁表指針和頁的數目。因此與其說初始化用戶地址空間,不如說初始化頁表,而頁表的數據結構中主要有虛地址,實地址,以及當前位是否有效,是否為臟頁…其中一些內容在本實驗中并無實際意義,比如臟頁,因為此時nachos系統都是直接將段數據放入物理內存中,因此不存在頁面置換的情況,也自然不存在臟頁寫回的問題。那么,在這個構造函數中,需要做的主要是利用文件的ReadAt()函數讀入可執行文件的段數據,由于nachos地址空間由段數據和堆棧指針構成,因此可據此獲得用戶地址空間的大小,從而計算出所需要的頁表數目,然后便可對頁表中的每一頁進行初始化即可,最后還有一步很重要的操作是將各段數據放入物理內存中(此時還不支持調頁的方式)。InitRegisters():cpu寄存器的初始化過程,其中不僅包括通用寄存器,還有很重要的兩個寄存器是PC寄存器和nextPC寄存器,兩者也同樣需要初始化,寄存器初始之后,還有需要初始化的是堆棧指針,也在這個函數中進行即可。RestoreState():修改機器的頁表指針指向當前進程的頁表即可。Run():進程的執行過程,這是一個很復雜的函數,其中涉及到每一個指令的執行過程,其中執行指令的過程均通過調用OneInstruction()函數進行。函數中執行的具體過程為:首先根據PC寄存器中存儲的地址,調用ReadMem()函數獲取對應地址所存儲的指令,然后分析并執行指令即可,最后還需要修改PC寄存器和其他寄存器的內容,使其保存各自對應指令的地址。需要補充一下的是ReadMem()函數,因為PC寄存器中保存的是虛地址,因此該函數的作用其實類似于MMU單元,需要將虛地址轉換為實地址,這個步驟主要是通過調用函數Translate()函數來實現的,其中主要過程為判斷是否存在快表以及是否命中快表,如果沒有命中則需要訪問頁表,并修改其響應的標識位。而ReadMem()函數除了調用Translate()函數以后,還進行了地址轉換過程中的各種異常處理,以及不同數據存儲方式的讀取過程(字節,字…)。
以上就是實驗六的相關內容,其更主要的一個作用是為了解進程的創建和執行所需要維護的一些數據結構和基本過程,為實驗七,八做鋪墊,因為很多東西在該實驗中還沒有實現,需要在接下來的兩個實驗中自己補充實現。
實驗七,八
最后兩個實驗是對上一個實驗的進一步理解和完善,上一個實驗更傾向于進程的創建和執行過程,最后兩個實驗則更側重于系統調用的實現和相關數據結構的使用過程。
系統調用
exec():該系統調用的功能時加載運行另一個應用程序,在Linux環境下使用時實現的方法往往是依然在此進程中,只不過用另一塊地址空間替換了當前進程的地址空間,因此當前進程中“exec(“xxx”)“之后的代碼一般是不執行的,因為地址空間已經改變,即代碼段和數據段等內容也均改變。但是此次實驗中使用nochos環境下,exec()的實現方法和Linux環境下的略有不同:首先依然需要從特定寄存器讀入exec()的參數(文件名稱),然后據此參數打開文件,裝入內存中,但是并不是替換當前進程的地址空間,而是建立一個新的進程,并分配空閑地址空間,有點類似于fork()調用,但是創建的新線程和原來的線程并沒有父子關系。而且,也不是立刻執行對應的新線程,只是將其放入就緒隊列中,等待被調度后執行。也正是因為沒有采用地址空間替換的方式,原線程中exec()調用之后的代碼依然會繼續執行。exit()和join():退出當前線程,并且保存進程的退出狀態,用狀態碼記錄下來。那么,進程都已經退出了,如何獲取對應的狀態碼呢?或者說狀態碼保存在哪里?這就引出了join()調用,其參數是進程pid,含義為等待對應的進程,并返回其退出狀態,記調用join()的線程為joiner,被等待的線程為joinee??墒?#xff0c;問題依然沒有解決,調用join()時joiner線程如何判斷當前joinee線程是否已經結束了呢?或者說它是該繼續等待還是直接獲取退出碼返回。為此,本實驗中為進程額外建立一種新的狀態–terminated狀態,即當進程該退出時不會立刻退出,而是進入terminated狀態,并且維護了一個terminated鏈表,這樣joiner線程就可以在調用join()時根據等待的pid遍歷terminated鏈表,如果存在自己等待的線程,那么就說明joinee已經執行結束,可以直接記錄joinee的狀態碼,并繼續執行當前線程后面的代碼;而如果不存在自己等待的線程,則需要進入等待狀態,直到joinee結束為止。因此,除了維護一個terminated鏈表,還需要維護一個waiting鏈表,用來記錄等待狀態的joiner。那么,什么時候使其退出等待狀態呢?邏輯也很簡單,當joinee線程退出時,遍歷waiting鏈表,如果找到等待自己的joiner線程,就可以喚醒它,并將自己的狀態碼傳遞給joiner線程;而如果沒有找到joiner線程,則直接進入terminated狀態即可。這樣就解決了join()和exit()調用的耦合關系。還有一個小細節就是,所有線程結束之后都會進入terminated狀態,并加入terminated鏈表,那么什么時候從鏈表中刪去該線程呢?本實驗中采用的一種暴力的方法,就是通過在調用exit()時,規定一個特殊的狀態碼,作為清空terminated鏈表,當然,這種方法存在很大的問題,不宜采用。。。
數據結構
pid相關:為了實現系統調用,除了邏輯和基本功能,還需要使用一些輔助的數據來記錄數據,比如進程pid,比如退出狀態碼…首先考慮pid的問題,pid主要用來每個線程的處理,以及join調用中joiner等待joinee時的參數,因此考慮用兩個屬性UserProgramId和waitingProcessSpaceId來分別表示線程對應的pid和join()時的參數joinee(沒有使用join調用的進程可忽略這個屬性),前者可以在分配pid時即可構建,而后者則在調用在使用join時賦值即可。進程狀態相關:之前討論中已經提及,為了給系統調用join()和exit()提供支持,需要為進程加一個terminated狀態,并且還需要在thread類中增加一個terminated鏈表和waiting鏈表,分別保存結束的進程以及調用join()后等待的進程。狀態碼相關:狀態碼只與exit()和join()調用相關,即分別對應joinee線程和joiner線程,也可以用兩個屬性exitCode和waitProcessExitCode來表示,前者可以在exit()傳入參數時賦值,后者則需要在調用join()時具體考慮:遍歷terminated鏈表中如果找到了對應的joinee,則可以直接獲取waitProcessExitCode,而如果沒有找到對應的joinee,則進入等待狀態,并加入waiting鏈表中。直到joinee線程結束時,在遍歷waiting鏈表時,再將對應的joiner線程的waitProcessExitCode設為當前線程的exitCode,并喚醒對應線程。
其他內容
除了上面的處理之外,還有一些額外的輔助信息,如AddrSpace文件中將文件中內存裝入主存,由于nachos原來只支持單進程,所以直接從虛地址的0地址開始即可,但是現在支持多進程同時存在,因此裝入主存的位置就需要根據利用頁的分配原則,將虛地址轉換為主存的實地址進行裝載。還有使系統調用和其他的指令處理過程統一起來的AdvancePC()函數等。
總結
到這里,nachos實驗就全部結束了。整體個過程下來,最大的感受就是對操作系統的進程管理和內存管理有了更深入的理解,從開始編寫源程序文件保存到磁盤上開始,涉及到文件的存儲方式,以及文件目錄表的管理,磁盤文件的分配等,當然,還有與文件相關的一些系統調用,如open(),create(),write(),copy()等;當源程序文件裝載到內存中時,靜態的文件就變成了動態的進程和線程,這里又涉及到包括進程的創建與執行,內存中為進程進行地址的分配,以及尋址時虛地址和實地址的轉換,進程的上下文切換過程等。當然,這一切的前提,都是基于操作系統首先進行裝載,因為本質上操作系統也是一個進程,上面的這些功能都是通過運行這個進程來實現的。因此當我們開機時,首先需要通過一個init()函數來將操作系統內核裝入內存中,然后運行操作系統進程來進行接下來的過程。
但是,說到底nachos只是一個簡單的操作系統的模擬,它并不是一個真正的可用的操作系統,甚至比起類似于Linux,Windows操作系統遠遠不及,本實驗的目的只是打開我對操作系統這個龐然大物的面紗,接下來需要我進一步去探索其中更加復雜的奧秘。對于操作系統的學習之路,才只是剛剛開始而已。
總結
以上是生活随笔為你收集整理的nachos的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。