1,原型
前面我們提到,可以用fork創建一個子進程。但是,這個子進程與原先的父進程共享程序段。也就是說兩個進程執行的是同一段代碼。這好像並沒有太大的用處。正常來說,我們希望的不是創建的新進程可以執行完全不同的功能嗎?這要怎麼做呢?
這就要用到我們今天講的exec系列函數。
通常的做法是,先用fork起一個子進程,再調用execXXX函數將子進程替換成一個指定的程序。這樣狸貓換太子之後,新的程序就獲得了原先子進程的pid和父進程。完全頂包了原先的子進程。
exec系列共有7個函數。今天的例子以最簡單的execl爲例子。7個函數的原型如下:
#include<unistd.h>
int execl(const char* pathname, const char* arg0, ...); //arg以空指針結尾
int execv(const char* pathname, char* const argv[]);
int execle(const char* pathname,const char* arg0, ...);//arg以空指針結尾,再接環境變量
int execve(const char* pathname, char* const argv[], char* const envp[]);
int execlp(const char* filename, const char* arg0, ...); //arg以空指針結尾
int execvp(const char* filename, char* const argv[]);
int fexecve(int fd, char* const argv[], char* const envp[]);
返回值:出錯返回-1,成功不返回。
2,例子:
2.1 hello程序
先裝備好一個簡單的hello程序做狸貓,便於待會被exec用來換太子。
先新建一個hello.c:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[]){
printf("Hello");
if (argc > 0){
printf(", %s!\n", argv[0]);
} else {
printf("\n");
}
}
它只是簡單滴打印第一個輸入參數,並在前面加上一個hello而已。
將其編譯成hello,就放在當前目錄下。
2.2 入正題
有了狸貓,開始準備太子。在study_Linux.c下寫入以下代碼。
int main(){
pid_t pid;
//用fork產生一個與自己一模一樣的子進程
if((pid = fork()) < 0) {
printf("fork error!\n");
exit(1);
} else if(pid == 0){ //注意,是在子進程內調用execl
//將子進程替換成hello,並給hello傳遞輸入參數Bihan,注意最後一個輸入參數一定是NULL
if(execl("./hello", "Bihan", NULL) < 0){
printf("execle error!\n");
exit(1);
}
}
printf("parent process\n");
//這裏waitpid還能等到hello,說明hello的pid就是原先子進程的pid,
//父進程就把hello當自己的子進程,狸貓換太子成功
if(waitpid(pid, NULL, 0) < 0){
printf("wait error!\n");
exit(1);
}else{
printf("wait end\n");
}
return 0;
}
執行結果:
➜ code ./study_linux
parent process
Hello, Bihan!
wait end
可以看到hello被執行,輸入參數也被傳遞,最後hello終止時父進程還能wait到。
注意一個細節。通常,當我們在命令行裏調用hello的時候,比如這樣:
➜ code ./hello Bihan
則hello的main函數的argv[0]並不是Bihan,而是“./hello”,當前程序名。所以剛纔的執行效果是這樣的:
➜ code ./hello Bihan
Hello, ./hello!
而我們在exec中指定hello的輸入參數時,argv[0]就是“Bihan”,沒有當前程序名自動成爲argv[0]這一說法了。
3,7個exec之間的關係
注意:只有execve是系統調用,其他的只是庫函數。其他6個最終也是通過調用execve實現的。
這組函數的名字是有規律的:
- 除了最後一個,其他都以exec開頭;
- l代表list,表示狸貓的輸入參數要一個一個列出來;與之相對,v代表vector,表示狸貓的輸入參數是個數組;
- e代表environment,環境 變量,表示重新設定狸貓的環境變量而不使用當前的環境變量;
- p代表exec的第一個輸入參數不是路徑而是文件名,其會在環境變量path的指定下去尋找該文件名的文件,p代表path;
- 最後一個的f代表文件描述符。所以總結起來指定狸貓有文件名、路徑名、文件描述符三種方法。