1. 程式人生 > >【nachos】山東大學作業系統課設實驗nachos系統(1):執行緒初探

【nachos】山東大學作業系統課設實驗nachos系統(1):執行緒初探

實驗內容:
下載並編譯nachos之後(注意只能在32位linux下成功編譯)
1. 跟蹤執行nachos之後,觀察以下函式的執行
(a) 上下文切換函式 SWITCH()
(b) 函式 ThreadRoot()

  1. 使用gdb執行nachos,回答一下問題:
    (a) 在你的nachos中,以下函式的地址是什麼:
    1
    i. InterruptEnable()
    ii. SimpleThread()
    iii. ThreadFinish()
    iv. ThreadRoot()
    並描述你怎樣找到他們的地址的.
    (b) 以下執行緒物件的地址是什麼?
    i. main thread
    ii. 被主執行緒創造的forked thread
    並描述怎麼找到他們的
    (c) 主執行緒第一次執行到SWITCH函式的時候,它執行到最後一條語句ret後,返回給cpu的地址是什麼?這個地址在程式中指向什麼?
    (d) 子執行緒第一次執行到SWITCH函式的時候,它執行到最後一條語句ret後,返回給cpu的地址是什麼?這個地址在程式中指向什麼?

實驗步驟與內容:
1、在threads目錄下使用make命令編譯
2、用gdb nachos命令開啟除錯
3、檢視原始碼的執行,熟悉執行流程
4、程式自main函式開始執行,在Initialize函式中,初始化了main執行緒的 物件。繼續執行執行ThreadTest函式後打印出內容
這裡寫圖片描述
可見本程式執行關鍵步驟在於ThreadTest函式。
這裡寫圖片描述
進入ThreadTest函式後可以發現,函式中完成了
①建立新的執行緒物件forked thread,
②呼叫物件的Fork方法,繫結SimpleThread這個函式,
③主程序執行函式SimpleThread。
這裡寫圖片描述
在SimpleThread函式中做的工作很簡單,只是打印出執行緒n的迴圈次數i,然後使執行緒yield。

接下來分析Yield函式和Fork函式。
Fork函式:
這裡寫圖片描述
可以看出,函式完成的工作是
①為執行緒分配棧空間,在StackAllocate函式中主要進行以下資料的初始化
這裡寫圖片描述
可以看出它為執行緒定義了整個生命週期各個階段的入口地址和引數,包括執行緒初始化函式ThreadRoot,fork函式中傳入的函式指標,執行緒結束函式ThreadFinish。
②將執行緒本身新增到scheduler的就緒佇列中等待排程。本步操作是原子操作不允許被中斷。

Yield函式:
這裡寫圖片描述
操作:①將當前執行緒新增到就緒佇列
②scheduler切換至下一個可以執行的執行緒。
綜上,兩步操作中途不允許打斷,且完成的工作是打斷當前執行緒,允許就緒佇列中下一個執行緒被排程執行,自身加入就緒佇列。

瞭解了以上兩個函式,可以看出,子執行緒被fork了之後,simpleThread函式將會在其生命週期中得以執行,且子執行緒加入就緒佇列,但此時並未得到執行的機會。而主執行緒執行SimpleThread函式,打出一句話後,呼叫yield後會將執行權交給子執行緒,子執行緒重複該過程,列印之後將執行權交換,直到執行完畢。以上過程再simpleThread中重複數次之後,子執行緒在simpleThread執行完畢後進入ThreadFinish的階段被回收,主執行緒因為還有其他操作所以繼續執行。

觀察SWITCH和ThreadRoot的執行:
SWITCH和ThreadRoot本身是彙編程式碼,需要進入swith.s檔案檢視
這裡寫圖片描述
觀察易知:switch函式完成的操作很簡單:將當前正在執行的狀態存入“舊執行緒”物件中,從“新執行緒”物件中取出執行狀態載入到暫存器,並跳轉到ra即將要執行的程式碼地址。

ThreadRoot:
這裡寫圖片描述
ThreadRoot是執行緒整個生命週期的一個整合,會跳轉到不同的函式入口以完成執行緒的整個生命週期。
5、在題目2(b)中的函式上設定斷點,記錄其地址即為答案

6、刪除上述斷點,在SWITCH和ThreadRoot和Initialize和ThreadTest上設定斷點
7、執行程式,程式進入Initailize,執行149行currentThread = new Thread(“main”);使用print currentThread即可檢視主執行緒物件地址
8、繼續執行程式,進入ThreadTest函式,執行46行Thread *t = new Thread(“forked thread”);使用print t檢視子執行緒物件地址
9、繼續執行,進入SWITCH函式,SWITCH和ThreadRoot是彙編程式碼,SWITCH負責切換當前兩個程序的上下文,ThreadRoot是整個程序的生命週期。單步ni執行至SWITCH切換到ThreadRoot時,是主程序切換至了子程序,子程序剛剛進入生命週期。此時ThreadRoot第一句的地址是SWITCH的ret,代表跳轉到以下地址執行。
10、再次執行,執行到SWITCH,因為兩個程序交換執行,所以這次是子程序交換至主程序。同上步,即為2(c),2(d)兩題的解。