本節書摘來自異步社群《unix環境進階程式設計(第3版)》一書中的第1章,第1.6節,作者:【美】w. richard stevens , stephen a.rago著,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視
1.程式
程式(program)是一個存儲在磁盤上某個目錄中的可執行檔案。核心使用exec函數(7個exec函數之一),将程式讀入記憶體,并執行程式。8.10節将說明這些exec函數。
2.程序和程序id
程式的執行執行個體被稱為程序(process)。本書的每一頁幾乎都會使用這一術語。某些作業系統用任務(task)表示正在被執行的程式。
unix系統確定每個程序都有一個唯一的數字辨別符,稱為程序id(process id)。程序id總是一個非負整數。
執行個體
圖1-6程式用于列印程序id。
圖1-6 列印程序id
如果将該程式編譯成a.out檔案,然後執行它,則有:
此程式運作時,它調用函數getpid得到其程序id。我們将會在後面看到,getpid傳回一個pid_t資料類型。我們不知道它的大小,僅知道的是标準會保證它能儲存在一個長整型中。因為我們必須在printf函數中指定需要列印的每一個變量的大小,是以我們必須把它的值強制轉換為它可能會用到的最大的資料類型(這裡是長整型)。雖然大多數程序id可以用整型表示,但用長整型可以提高可移植性。
3.程序控制
有3個用于程序控制的主要函數:fork、exec和waitpid。(exec函數有7種變體,但經常把它們統稱為exec函數。)
unix系統的程序控制功能可以用一個簡單的程式說明(見圖1-7)。該程式從标準輸入讀取指令,然後執行這些指令。它類似于shell程式的基本實施部分。
圖1-7 從标準輸入讀指令并執行
在這個30行的程式中,有很多功能需要考慮。
用标準i/o函數fgets從标準輸入一次讀取一行。當鍵入檔案結束符(通常是ctrl+d)作為行的第一個字元時,fgets傳回一個null指針,于是循環停止,程序也就終止。第18章将說明所有特殊的終端字元(檔案結束、倒退字元、整行擦除等),以及如何改變它們。
因為fgets傳回的每一行都以換行符終止,後随一個null位元組,是以用标準c函數strlen計算此字元串的長度,然後用一個null位元組替換換行符。這樣做是因為execlp函數要求的參數是以null結束的而不是以換行符結束的。
調用fork建立一個新程序。新程序是調用程序的一個副本,我們稱調用程序為父程序,新建立的程序為子程序。fork對父程序傳回新的子程序的程序id(一個非負整數),對子程序則傳回0。因為fork建立一個新程序,是以說它被調用一次(由父程序),但傳回兩次(分别在父程序中和在子程序中)。
在子程序中,調用execlp以執行從标準輸入讀入的指令。這就用新的程式檔案替換了子程序原先執行的程式檔案。fork和跟随其後的exec兩者的組合就是某些作業系統所稱的産生(spawn)一個新程序。在unix系統中,這兩部分分離成兩個獨立的函數。第8章将對這些函數進行更多說明。
子程序調用execlp執行新程式檔案,而父程序希望等待子程序終止,這是通過調用waitpid實作的,其參數指定要等待的程序(即pid參數是子程序id)。waitpid函數傳回子程序的終止狀态(status變量)。在我們這個簡單的程式中,沒有使用該值。如果需要,可以用此值準确地判定子程序是如何終止的。
該程式的最主要限制是不能向所執行的指令傳遞參數。例如不能指定要列出目錄項的目錄名,隻能對工作目錄執行ls指令。為了傳遞參數,先要分析輸入行,然後用某種約定把參數分開(可能使用空格或制表符),再将分隔後的各個參數傳遞給execlp函數。盡管如此,此程式仍可用來說明unix系統的程序控制功能。
如果運作此程式,将得到下列結果。注意,該程式使用了一個不同的提示符(%),以差別于shell的提示符。
^d表示一個控制字元。控制字元是特殊字元,其構成方法是:在鍵盤上按下控制鍵——通常被标記為control或ctrl,同時按另一個鍵。ctrl+d或^d是預設的檔案結束符。在第18章中讨論終端i/o時,會介紹更多的控制字元。
4.線程和線程id
通常,一個程序隻有一個控制線程(thread)——某一時刻執行的一組機器指令。對于某些問題,如果有多個控制線程分别作用于它的不同部分,那麼解決起來就容易得多。另外,多個控制線程也可以充分利用多處理器系統的并行能力。
一個程序内的所有線程共享同一位址空間、檔案描述符、棧以及與程序相關的屬性。因為它們能通路同一存儲區,是以各線程在通路共享資料時需要采取同步措施以避免不一緻性。
與程序相同,線程也用id辨別。但是,線程id隻在它所屬的程序内起作用。一個程序中的線程id在另一個程序中沒有意義。當在一程序中對某個特定線程進行處理時,我們可以使用該線程的id引用它。
控制線程的函數與控制程序的函數類似,但另有一套。線程模型是在程序模型建立很久之後才被引入到unix系統中的,然而這兩種模型之間存在複雜的互動,在第12章中,我們會對此進行說明。