APUE學習 程序控制

2021-07-10 21:48:45 字數 4284 閱讀 8989

程序識別符號在系統中是唯一的。unix採用延遲技術來分配pid。因為,如果乙個程序終止了,馬上把他的pid分配給新的程序,而且這個新程序與舊程序要做一樣的事。那麼別人就不知道這是新程序還是舊程序在做了。(類似於tcp4次揮手的最後一步。)

還有一些特殊的程序,例如pid為0的程序,這個可以看成是乙個核心的一部分,他主要用來排程。還有pid為1的程序,這個程序就是乙個普通的程序了,但是擁有root許可權,主要用來當做daemon。1號程序是核心載入完畢之後啟動第乙個程序,他可以用來設定使用者的啟動環境,啟動核心模組等等。而且他是所有程序的父程序(除了0號程序)

fork之後,子程序會複製父程序的data space 與statck,但是現代實現中採用copy-on-write,即子程序在改變的時候才會去擁有自己的程序空間。

注意點:

對於書上figure 8.1

注意到這兩個輸出的不同:

1.第乙個只是輸出了乙個 before fork,而第二個輸出了兩個 before fork。

這是因為在第乙個中,我們將標準i/o連線到了終端中,這樣標準i/o就是乙個行緩衝。所以在呼叫printf時,會自動重新整理緩衝,這樣在程序中就沒有這個資料了。但是在第二個中,標準i/o被重定向到了檔案中,這樣標準i/o就是全緩衝了,也就是說除非緩衝區滿,或者呼叫fflush,否則我們是不會重新整理緩衝區的。之後我們呼叫fork建立子程序,子程序會複製父程序的data space ,這樣緩衝區中的資料也被複製到子程序中,在子程序退出時因為會自動呼叫fflush,所以會再次重新整理緩衝,造成再次輸出before fork

2.注意到write的輸出在這兩個中都只出現了一次。

這是因為write是不帶緩衝的,所以不管寫到哪都會只寫一次。

思考:1.可以在子程序中呼叫_exit,這樣就不會清空緩衝。

2.printf中不寫\n,這樣即使是連線到終端也會輸出兩個before fork

在fork之後,子程序與父程序會共享開啟檔案表。如圖:

說明:

因為子程序會複製父程序的檔案描述符,這樣操作不當會造成輸出的混亂。所以處理檔案描述的方法一般有兩個:

1.父程序等待子程序完成。注意子程序會影響到檔案偏移。

2.父子程序執行不同的程式段。例如子程序fork之後呼叫exec。回憶檔案描述符的flag中可能會有o_clo***ec,這樣子程序exec之後,對應的檔案描述符就被關閉了。這樣父子程序就會使用不衝突的檔案描述符。

1.父子程序執行不同的**段

2.子程序要執行不同的程式,可以通過fork之後呼叫exec來讓新程式執行

vfork是為了簡化fork之後呼叫exec的步驟。vfork保證了子程序先進行,直到子程序執行了exit或者exec。vfork實現中,子程序會借用父程序的位址空間,也就是說如果在子程序中改變一些值,會影響到父程序中的值。所以一般vfork是為了spawn用的,即fork-exec。

不管如何退出,kernel最終都會執行相同的**段,即關閉檔案描述符,是否記憶體空間等等。

在乙個正常的退出中,是核心,而不是程序來保障終止狀態。

#include 

pid_t wait(int

*statloc);

pid_t waitpid(pid_t pid, int

*statloc, int options);

//兩個函式返回值:若成功則返回程序id,若出錯則返回-1

waitid類似於waitpid

idtype:指出要等待的型別,

id:程序id

infop:有更一步的資訊

options:

競爭條件:當有多個程序嘗試使用共享的資料做些事情,並且最後結果依賴於這些程序的執行順序。

exec函式族,主要用於在父程序fork之後,呼叫exec來執行另乙個程式,新的程式從它自己的main函式出開始執行。呼叫exec並不會改變子程序的pid,exec函式僅僅改變了子程序的text,data, heap and stack。

說明:

int setuid(uid_t uid);

int setgid(gid_t gid);

說明:

int seteuid(uid_t uid);

int setegid(gid_t gid);

說明:對於非root許可權程序可以設定他的euid為ruid或者suid。

對於root許可權程序只是設定euid為uid

注意使用exec函式乙個直譯器檔案的情況

在exec乙個直譯器檔案的時候,exec的arg[0]會被直譯器檔案的路徑名替代,並且exec的開始的引數會變為直譯器檔案中的那一行,然後exec中原有的引數會一次右移幾位。

直譯器檔案主要用於指令碼中。

使用system的優勢在於他處理了所有的錯誤,並且所有的訊號處理。

說明:

對於figure 8.25的理解:

注意理解,這裡我們的使用者shell的ruid與euid都是205,然後執行tsys,這時因為tsys設定了set uid,所以此時我們程序的euid變為了0,然後又去呼叫了system函式,而system函式又使用了printuids,在printuids我們的許可權是ruid = 205, euid = 0。但是我們執行printuids並不用這麼高的許可權,我們只需要205的euid許可權就可以執行了。

所以,在使用system要注意的是,不要去在乙個設定了set uid的程式中呼叫system,這樣會造成system呼叫的那個函式也具有比較高的許可權。這種情況要使用fork與exec,即fork之後,使用set***等函式降低許可權,再去exec。

int nice(int incr);
說明:只有root許可權的程序可以root來提高自己的優先順序,其他許可權的使用者只能用來降低自己的優先順序。

times函式獲得程序的相關時間。注意times返回的就是牆上時鐘時間,所以tms結構體中沒有牆上時鐘時間。

說明:程序的三種狀態為阻塞、就緒、執行。

時鐘時間 = 阻塞時間 + 就緒時間 +執行時間

使用者cpu時間 = 執行狀態下使用者空間的時間

系統cpu時間 = 執行狀態下系統空間的時間。

使用者cpu時間+系統cpu時間=執行時間。

linux中程序許可權這一塊的主要思想是:最小許可權思想。也就是說我要幹一件事,那麼要用能做成這件事的最小許可權去做。所以有setuid,seteuid函式,就是讓我們在fork程式之後,呼叫這些函式,給子程序適當的許可權,然後再去exec。這也是system的乙個缺陷,如果在乙個設定了setuid的程式中呼叫system,我們是不可以給system呼叫的那個函式以適當的許可權去做事的。

綜上:記住linux中檔案的許可權,程序的許可權以及最小許可權思想。同時記住linux中一切皆檔案的思想。

1.在乙個function中呼叫vfork,並且返回。

首先在乙個function中使用vfork之後,產生乙個子程序,這個子程序共享了父程序的stack,包括函式呼叫棧。由於vfork首先執行子程序,所以會返回子程序的那個值,然後父程序返回時由於子程序已經把呼叫棧返回了,會出現segment fault錯誤。

還有一種情況,子程序可以將stack空間都寫上自己的值,然後從function中返回,這是main函式棧後面的資料都被改寫,也就是說父程序想要在function呼叫後返回,但是這個時候棧空間被子程序重寫了,他就找不到要回到**去了,有可能跑到別的地方去了。

APUE學習筆記 程序控制

1.getpid可以獲取程序id。getppid可以獲取程序呼叫程序的id。2.fork函式 一次呼叫,兩次返回 返回0是在子程序中。返回其他值在父程序中。如果大於0為子程序id 否則失敗。3.子程序獲得了父程序的資料空間 data,bss 堆,棧的副本。程序之間共享正文段。4.目前的實現一般不進行...

APUE 程序控制 中

當乙個程序正常或異常終止時會向父程序傳送sigchld訊號。對於這種訊號系統缺省會忽略。呼叫wait waidpid的程序可能會 include include pid t wait int statloc pid t waitpid pid t pid,int statloc,int option...

linux學習之程序控制

首先交代幾個基本概念 1.程式 程式是乙個儲存在磁碟上某個目錄中的可執行檔案 2.程序 程式的執行例項被稱為程序 3.程序id 每個程序都有乙個非負整數型表示的唯一程序id 除了程序id,每個程序還有一些其他識別符號,下面是相關函式 includepid t getpid void 返回值 程序的i...