linux學習之程序控制
首先交代幾個基本概念 1.程式:程式是一個儲存在磁碟上某個目錄中的可執行檔案 2.程序:程式的執行例項被稱為程序 3.程序ID:每個程序都有一個非負整數型表示的唯一程序ID 除了程序ID,每個程序還有一些其他識別符號,下面是相關函式
#include<unistd.h> pid_t getpid(void); 返回值:程序的id pid_t getppid(void); 返回值:程序父程序的id uid_t getuid(void); 返回值:程序實際使用者id uid_t geteuid(void); 返回值:程序有效使用者id gid_t getgid(void); 返回值:程序實際組id gid_t getegid(void); 返回值:程序有效值id
建立程序 一個現有的程序可以呼叫fork函式建立一個新程序
#include<unistd.h>
pid_t fork(void);
返回值:子程序返回0,父程序返回子程序id,出錯返回-1
fork函式例項
int main() { pid_t pid; int i=1; if((pid=fork())<0) //建立子程序 { perror("fork"); } else if(pid==0) //子程序中執行i++ { i++; } else //父程序休眠2s { sleep(2); } exit(0); }
fork有以下兩種用法 (1)父程序希望複製自己,使子程序和父程序執行不同的程式碼段。這在網路伺服器中是常見的,父程序等待客戶端的請求,當請求到來時,父程序呼叫fork,使子程序處理該請求。父程序則繼續等待下一個請求。 (2)一個程序要執行不同的程式,在這種情況下,子程序fork返回後立即呼叫exex函式族(後面會提到)。
程序的終止 程序有5種正常及3種異常終止方式。5種正常終止方式如下 1)main函式執行return語句。 2)呼叫exit函式,此操作包括呼叫各終止處理程式,然後關閉I/O流。不過由於此函式在ISO C中定義,而ISO C並不處理檔案描述符,多程序及作業控制,所以對於Linux系統而言,它是不完整的。 3)呼叫_exit或者 _Exit函式,此函式無需執行終止處理程式。在linux下這兩個函式是同義的。_exit函式由exit呼叫。 4)程序的最後一個執行緒在其啟動例程中執行return語句。 5)程序的最後一個執行緒呼叫pthread_exit函式。
3種異常終止如下。 1)呼叫abort。它產生SIGABRT訊號 2)當程序收到某些訊號時,呼叫abort就是一種特例。 3)最後一個執行緒對“取消”請求做出響應。
不管程序如何終止,最後都會執行核心中同一段程式碼。這段程式碼為相應程序關閉所有開啟描述符,釋放它所用的儲存器。 對於父程序已經終止的子程序,它們的父程序全部改為init程序。而父程序是通過wait和waitpid函式來獲取子程序的終止狀態的。如何父程序沒有對已經終止的子程序進行一些處理,例如釋放其所佔用的資源,則該子程序為僵死程序。
wait和waitpid函式 當一個程序終止時,核心就會向其父程序傳送SIGCHLD訊號,呼叫wait和waitpid函式後。 1)如果其所有的子程序還在執行,則阻塞 2)如果子程序已經終止,則立即返回 3)如果沒有任何子程序,則出錯
#include<sys/wait.h>
pid_t wait(int *statloc);
pid_t waitpid(pid_t pid,int statloc,int options);
返回值:成功返回程序ID,失敗返回0或-1
競爭條件 當多個程序都企圖對共享資料進行某種處理,而最後的結果又取決於程序的執行順序時,我們認為發生了競爭條件。如果在fork之後的某種邏輯顯示或隱示地依賴於在fork之後是父程序還是子程序先執行,那麼fork函式就會是競爭條件的活躍滋生地。通常我們無法預料哪個程序先執行。即使我們知道哪個先執行,在該程序執行後所發生的事情也依賴於系統負載以及核心的排程演算法。 為了避免競爭條件或者是輪詢,在多個程序之間需要某種形式的的訊號傳送和接收的的方法。例如訊號機制,有興趣的可以自己查詢書籍,這裡就不闡述了。
exec函式族 fork函式是用於建立一個子程序,該子程序幾乎是父程序的副本,而有時我們希望子程序去執行另外的程式,exec函式族就提供了一個在程序中啟動另一個程式執行的方法。它可以根據指定的檔名或目錄名找到可執行檔案,並用它來取代原呼叫程序的資料段、程式碼段和堆疊段,在執行完之後,原呼叫程序的內容除了程序號外,其他全部被新程式的內容替換了。另外,這裡的可執行檔案既可以是二進位制檔案,也可以是Linux下任何可執行指令碼檔案。 這一塊內容比較多,有興趣可以自己查。
int execl(const char *path, const char *arg, ...)
int execv(const char *path, char *const argv[])
int execle(const char *path, const char *arg, ..., char *const envp[])
int execve(const char *path, char *const argv[], char *const envp[])
int execlp(const char *file, const char *arg, ...)
int execvp(const char *file, char *const argv[])
總而言之對於程序,我們必須熟練掌握的是fork,exec系列,wait,waitpid和_exit函式。