目錄
多進程程序替換
多進程程序替換原理
進程程序替換函數詳解
execl&execv
execlp&execvp
execle&execvpe?
execve
多進程程序替換
- 我們想要進程替換的同時不影響舊的進程(使用多進程版)
- fork創建子進程,讓子進程去替換執行新程序(因為替換進程本身不會創建新的進程)
- 父進程依舊執行舊的進程,且等待子進程(非阻塞等待)
- 父進程只等待子進程(阻塞等待)
- 子進程可以替換系統指令,也可以替換我們自己的程序,只要是一個可執行程序都可以替換。
- 兩全其美:既讓子進程完成了任務,又不能讓父進程受到影響
說明fork創建子進程完成任務:
- 讓子進程執行父進程代碼的一部分
- 讓子進程執行一個全新的程序
- 基于進程間的獨立性原則。
- fork創建的子進程默認在不修改的前提下,父子進程的數據和代碼時共享的。
- 子進程發生了進程替換,相當于發生寫入,發生了寫時拷貝。
- 執行一個全新的程序,父子進程是獨立的,所以不僅數據要寫時拷貝,代碼也要發生寫時拷貝。只要程序替換成功了,父子進程無論是代碼/數據在內核數據結構層面上,數據代碼層面上徹底分開了。
子進程發生程序替換:
- 共享父進程的數據代碼
- 暫停了把新程序的代碼和數據從磁盤到內存的加載/寫入
- 發生寫時拷貝
- 開啟加載/寫入(頁表的權限會改變)
- 重新建立映射關系
1: testexec.c 1 #include<stdio.h>2 #include<unistd.h>3 #include<stdlib.h>4 #include<sys/types.h>5 #include<sys/wait.h>6 7 int main()8 {9 printf("testexec.... begin!\n");10 pid_t id = fork();11 if(id == 0)12 {13 //child14 sleep(2);15 execl("/usr/bin/ls","ls","-l","-a",NULL); 16 exit(1);17 }18 //father19 int status = 0;20 pid_t rid = waitpid(id,&status,0);21 if(rid > 0)22 {23 printf("father wait success!,child exit code: %d\n",WEXITSTATUS(status));24 }25 printf("testexec... end!\n");26 return 0;27 }//測試失敗
execl("/usr/bin/lsss","lsss","-l","-a",NULL);
【測試成功】細看退出碼
【測試失敗】細看退出碼
?
多進程程序替換原理
- 用fork創建子進程后執行的是和父進程相同的程序(但有可能執行不同的代碼分支)
- 子進程往往要調用一種exec函數以執行另一個程序。
- 當進程調用一種exec函數時,該進程的用戶空間代碼和數據完全被新程序替換。
- 從新程序的啟動,程開始執行。
- 調用exec并不創建新進程,所以調用exec前后該進程的id并未改變。
進程程序替換函數詳解
前篇粗略的介紹了下替換函數,現在一個一個詳解介紹。使用所有的替換方法,并且認識函數參數的含義
- OS中默認進程程序替換函數有6個庫函數和1個系統調用函數。
- 其實有六種以exec開頭的函數,統稱exec函數
#include <unistd.h>`
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ...,char *const envp[]);int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],char *const envp[]);
//系統調用函數
int execve(const char *path, char *const argv[], char *const envp[]);
execl&execv
- l:list列表
- int execl(const char *path, const char *arg, ...);?
- path:表示替換程序的路徑(絕對/相對路徑均可)??怎樣找到可執行程序需告知
- arg:可變參數,在命令行中怎么執行,就怎么傳參。??你想怎么執行
- arg形成命令行參數表傳給ls指令的可執行程序main函數接收使用
- 注意?最后必須以NULL結尾
V:Vector動態數組- int execv(const char *path, char *const argv[ ]);
- path:表示替換程序的路徑(絕對/相對路徑均可)??怎樣找到可執行程序需告知
- argv:指針數組(可變參數與其一個一個傳參,直接放到數組里面,傳數組即可)(帶入命令行參數表)
- argv被當作命令行參數表傳給ls指令的可執行程序main函數接收使用
- 字符串的類型是const char*變成char*需要強轉
- 注意?最后必須以NULL結尾
- 這兩個函數只是在傳參形式上發生了變化,實際上沒有區別。
1 #include<stdio.h>2 #include<unistd.h>3 #include<stdlib.h>4 #include<sys/types.h>5 #include<sys/wait.h>6 7 int main()8 {9 printf("testexec.... begin!\n");10 pid_t id = fork();11 if(id == 0)12 {13 //child14 sleep(2);15 execl("/usr/bin/ls","ls","-l","-a",NULL); //? 16 exit(1);17 }//1 #include<stdio.h>2 #include<unistd.h>3 #include<stdlib.h>4 #include<sys/types.h>5 #include<sys/wait.h>6 7 int main()8 {9 printf("testexec.... begin!\n");10 pid_t id = fork();11 if(id == 0)12 {13 //child14 sleep(2);15 char *const argv[] =16 {17 (char*)"ls",18 (char*)"-l", 19 (char*)"-a",20 (char*)"--color",21 NULL22 };23 execv("/usr/bin/ls",argv); //?24 exit(1);25 }26 //father27 int status = 0;28 pid_t rid = waitpid(id,&status,0);29 if(rid > 0)30 {31 printf("father wait success!,child exit code: %d\n",WEXITSTATUS(status));32 }33 printf("testexec... end!\n");34 return 0; 35 }
execlp&execvp
- p:環境變量PATH
- 帶p的函數不用帶絕對/相對路徑傳遞參數了,表示用戶可以不傳遞替換程序的路徑(但是要傳遞可執行程序的文件名file)
- 用戶可以不傳遞要執行的文件路徑(文件名要傳),直接告訴exec*,我要執行誰即可。
- p:查找這個程序,系統會自動在環境變量PATH中進行查找。
- int execlp(const char *file, const char *arg, ...);
- int execvp(const char *file, char *const argv[ ]);
1 #include<stdio.h>2 #include<unistd.h>3 #include<stdlib.h>4 #include<sys/types.h>5 #include<sys/wait.h>6 7 int main()8 {9 printf("testexec.... begin!\n");10 pid_t id = fork();11 if(id == 0)12 {13 //child14 sleep(2);15 execlp("ls","ls","-l","-a",NULL); //? 16 exit(1);17 }//1 #include<stdio.h>2 #include<unistd.h>3 #include<stdlib.h>4 #include<sys/types.h>5 #include<sys/wait.h>6 7 int main()8 {9 printf("testexec.... begin!\n");10 pid_t id = fork();11 if(id == 0)12 {13 //child14 sleep(2);15 char *const argv[] =16 {17 (char*)"ls",18 (char*)"-l", 19 (char*)"-a",20 (char*)"--color",21 NULL22 };23 execvp("ls",argv); //?24 exit(1);25 }26 //father27 int status = 0;28 pid_t rid = waitpid(id,&status,0);29 if(rid > 0)30 {31 printf("father wait success!,child exit code: %d\n",WEXITSTATUS(status));32 }33 printf("testexec... end!\n");34 return 0; 35 }
execle&execvpe?
- e:environment環境變量
- int execle(const char *path, const char *arg, ...,char *const envp[ ]);
- int execvpe(const char *file, char *const argv[ ],char *const envp[ ]);
- bash有環境變量,也可以獲取命令行參數
- bash創建父進程
- fork創建子進程
- 通過exec*等函數將環境變量表和命令行參數表交給可執行程序
- 子進程運行起來,并使用兩張表
execve
🙂感謝大家的閱讀,若有錯誤和不足,歡迎指正。 下篇收尾?