exec函數族
函數族說明
fork() 函數用於建立一個新的子進程,該子進程幾乎複製了父進程的全部內容,但是,這個新建立的子進程如何執行呢?exec 函數族就提供了一個在進程中啟動另一個程式執行的方法。它可以根據指定的檔案名稱或目錄名找到可執行檔,並用它來取代原調用進程的資料區段、程式碼片段和堆棧段,在執行完之後,原調用進程的內容除了進程號外,其他全部被新的進程替換了。另外,這裡的可執行檔既可以是二進位檔案,也可以是Linux下任何可執行檔指令檔。
在 Linux 中使用exec函數族主要有兩種情況:
● 當進程認為自己不能再為系統和使用者做出任何貢獻時,就可以調用 exec 函數族中的任意一個函數讓自己重生。
● 如果一個進程想執行另一個程式,那麼它就可以調用 fork() 函數建立一個進程,然後調用 exec 函數族中的任意一個函數,這樣看起來就像通過執行應用程式而產生了一個新進程(這種情況非常普遍)。
函數族文法
實際上,在Linux中並沒有exec()函數,而是由6個以 exec 開頭的函數,它們之間的文法有細微差別。下表列出了 exec 函數族的6個成員函數的文法:
這6個函數在函數名和使用文法的規則上都有細微的區別,下面就從可執行檔尋找方式、參數傳遞方式和環境變數這幾個方面進行比較。
● 尋找方式:表1中的前4個函數的尋找方式都是完整的檔案目錄路徑,而最後兩個函數(也就是以 p 結尾的兩個函數)可以只給出檔案名稱,系統就會自動按照環境變數“$PATH” 所指定的路徑進行尋找。
● 參數傳遞方式:exec函數族的參數傳遞有兩種:一種是逐個列舉的方式,而另一種則是將所有參數整體構造指標數組傳遞。在這裡是以函數名的第5位字母來區分的,字母為 "l"(list)的表示逐個列舉參數的方式,其文法為const char *arg;字母為“v”(vector)的表示將所有參數整體構造指標數組傳遞,其文法為 char *const argv[]。這裡的參數實際上就是使用者在使用這個可執行檔時所需的全部命令選項字串(包括該可執行程式命令本身)。要注意的是,這些參數必須以NULL結束。
● 環境變數: exec函數族可以預設系統的環境變數,也可以傳入指定的環境變數。這裡以 “e”(environment)結尾的兩個函數 execle()和 execve()就可以在 envp[]中指定當前進程所使用的環境變數。
表2再對這6個函數中的函數名和對應文法做了一個小結,主要指出了函數名中每一位對應所表明的含義,以此表加以記住這6個函數。
事實上,這6個函數中真正的系統調用只有execve(),其他5個都是庫函數,它們最終都會調用execve()這個系統調用。在使用exec函數族時,一定要加上錯誤判斷語句。exec 很容易執行失敗,其中最常見的原因有:
① 找不到檔案或路徑,此時 errno 被設定為 ENOENT。
② 數組argv 和envp 忘記用NULL結束,此時,errno被設定為 EFAUL。
③ 沒有對應可執行檔的運行許可權,此時 errno 被設定為EACCES。
基礎實驗
實驗1
本實驗是為了說明如何使用檔案名稱來尋找可執行檔,同時使用參數列表的方式。這裡用的函數是 execlp()。程式碼如下:
在該程式中,首先使用 fork()函數建立一個子進程,然後在子進程中使用 execlp()函數。可以看到,這裡的參數列表列出了在 shell 中使用的命令名和選項,並且當使用檔案名稱進行尋找時,系統會在預設的環境變數PATH中尋找該可執行檔。
使用命令:gcc execlp.c -o execlp編譯後,然後再執行,結果如:
使用env命令,可以查看到環境變數的路徑名
此程式的執行結果與在shell中直接輸入命令“ps -ef”是一樣的,當然,在不同系統的不同時刻可能會有不同的結果。
實驗2
本實驗實現的功能和實驗1的一樣,不同的是使用的函數不同。本實驗將使用完整的檔案目錄來尋找對應的可執行檔。注意,目錄必須以“/”開頭,否則將其視為檔案名稱。程式碼如下:
編寫儲存源檔案,然後使用命令:gcc execl.c -o execl編譯,接著執行命令:./execl,可以看到實驗結果和實驗1一樣
實驗3
本實驗是利用execle()函數將環境變數添加到建立的子進程中,這裡的“env”是查看當前進程環境變數的命令,實驗代碼如下:
編寫儲存源檔案後,使用命令:gcc execle.c -o execle,再執行命令:./execle,執行結果如
實驗4
本實驗實現功能和實驗3一樣,不同的是使用的execve()函數,通過構造指標數組的方式來傳遞參數,注意參數列表一定要以NULL作為結尾標識符,實驗代碼如下:
編寫儲存源檔案,使用命令:gcc execve.c -o execve,再執行命令:./execve,結果如下:
到此關於進程的執行實驗完畢,下一節學習進程的終止