作業系統:三個簡單的部分。 第 3 部分:流程 API(翻譯)

操作系統簡介

嘿哈布爾! 我想提請您注意一系列文章——我認為是一本有趣的文學作品的翻譯——OSTEP。 本材料非常深入地討論了類 unix 操作系統的工作,即與進程、各種調度程序、內存和構成現代操作系統的其他類似組件一起工作。 你可以在這裡看到所有材料的原件 這裡. 請注意,翻譯是非專業的(相當隨意),但我希望我保留了一般意思。

關於這個主題的實驗室工作可以在這裡找到:

其他部分:

您也可以查看我的頻道 電報 =)

警報! 本次講座有實驗室! 看 github

流程API

讓我們來看一個在 UNIX 系統中建立進程的範例。 它透過兩個系統呼叫發生 叉子() и 執行().

呼叫 fork()

作業系統:三個簡單的部分。 第 3 部分:流程 API(翻譯)

考慮一個進行 fork() 呼叫的程式。 其執行結果如下。

作業系統:三個簡單的部分。 第 3 部分:流程 API(翻譯)

首先,我們進入 main() 函數並將字串列印到螢幕上。 該行包含進程標識符,在原始版本中稱為 PID 或進程標識符。 此標識符在 UNIX 中用於指稱進程。 下一個命令將呼叫 fork()。 此時,該流程的幾乎完全相同的副本已建立。 對於作業系統來說,看起來系統上運行著同一個程式的 2 個副本,這將依序退出 fork() 函數。 新建立的子進程(相對於建立它的父進程)將不再執行,從 main() 函數開始。 應該記住,子程序並不是父進程的精確副本;特別是,它有自己的位址空間、自己的暫存器、指向可執行指令的指標等。 因此,傳回給 fork() 函數呼叫者的值將會不同。 特別是,父進程將收到子進程的 PID 值作為返回值,而子進程將收到等於 0 的值。使用這些返回碼,您可以分離進程並強制每個進程執行自己的工作。 然而,這個程序的執行並沒有嚴格定義。 分成 2 個進程後,作業系統開始監視它們,並規劃它們的工作。 如果在單核心處理器上執行,其中一個進程(在本例中為父進程)將繼續工作,然後子進程將接收控制權。 重新啟動時,情況可能會有所不同。

調用等待()

作業系統:三個簡單的部分。 第 3 部分:流程 API(翻譯)

考慮以下程序。 在這個程式中,由於存在一個調用 等待() 父進程將始終等待子進程完成。 在這種情況下,我們將在螢幕上得到嚴格定義的文字輸出

作業系統:三個簡單的部分。 第 3 部分:流程 API(翻譯)

exec() 呼叫

作業系統:三個簡單的部分。 第 3 部分:流程 API(翻譯)

考慮挑戰 執行()。 當我們想要運行一個完全不同的程式時,這個系統呼叫非常有用。 這裡我們將調用 execvp() 運行 wc 程序,這是一個字數統計程序。 呼叫 exec() 時會發生什麼事? 此呼叫將傳遞可執行檔的名稱和一些參數作為參數。 之後,載入該可執行檔中的程式碼和靜態數據,並覆寫其自己的程式碼段。 剩餘的記憶體區域,例如堆疊和堆,將被重新初始化。 之後,作業系統簡單地執行該程序,並向其傳遞一組參數。 所以我們並沒有創建一個新的進程,我們只是將目前正在運行的程式轉化為另一個正在運行的程式。 在後代中執行 exec() 呼叫後,看起來好像原始程式根本沒有運行。

這種啟動複雜性對於 Unix shell 來說是完全正常的,並且允許該 shell 在呼叫後執行程式碼 叉子(),但在通話之前 執行()。 此類程式碼的一個範例是在啟動程式之前調整 shell 環境以滿足正在啟動的程式的需求。

壳类 - 只是一個用戶程式。 她向您展示邀請行並等待您在其中寫一些內容。 在大多數情況下,如果您在那裡寫下程式的名稱,shell 將找到它的位置,呼叫 fork() 方法,然後呼叫某種類型的 exec() 來建立一個新進程並使用等待()呼叫。 當子進程退出時,shell將從wait()呼叫返回並再次列印提示符號並等待輸入下一個命令。

fork() 和 exec() 分割允許 shell 執行下列操作,例如:
wc 檔 > new_file.

在此範例中,wc 程式的輸出被重定向到檔案。 shell 實現這一點的方式非常簡單 - 透過在呼叫之前建立一個子進程 執行(),shell關閉標準輸出並開啟文件 新文件,因此,進一步運行的程式的所有輸出 wc 將被重定向到檔案而不是螢幕。

Unix管道 以類似的方式實現,不同之處在於它們使用 pipeline() 呼叫。 在這種情況下,進程的輸出流將連接到位於核心中的管道佇列,另一個進程的輸入流將連接到該管道隊列。

來源: www.habr.com

添加評論