嵌入式Linux:子進(jìn)程執(zhí)行新程序
在 Linux 中,子進(jìn)程在創(chuàng)建后可以通過 exec 系列系統(tǒng)調(diào)用執(zhí)行一個全新的程序。這種情況下,子進(jìn)程會替換原有的代碼和數(shù)據(jù)段,運(yùn)行一個新的可執(zhí)行程序,但它的進(jìn)程 ID(PID)保持不變。exec 系列調(diào)用包括多個變體,常見的有 execl()、execv()、execle()、execve() 等,它們的主要區(qū)別在于參數(shù)傳遞方式不同。
子進(jìn)程執(zhí)行新程序的流程如下:
創(chuàng)建子進(jìn)程:使用 fork() 創(chuàng)建子進(jìn)程。
調(diào)用 exec:在子進(jìn)程中調(diào)用 exec 執(zhí)行新程序。
替換子進(jìn)程的內(nèi)存映像:exec 會替換子進(jìn)程的整個內(nèi)存空間,包括代碼段、數(shù)據(jù)段、堆棧等,只保留進(jìn)程的 PID 和一些特定屬性。
父進(jìn)程繼續(xù)執(zhí)行:父進(jìn)程保持不變,繼續(xù)執(zhí)行它的代碼,直到調(diào)用 wait() 等待子進(jìn)程結(jié)束。
exec 系列函數(shù)通過不同的方式傳遞參數(shù)和環(huán)境變量,能夠?qū)崿F(xiàn)靈活的程序替換。具體函數(shù)如下:
execve() 是最基礎(chǔ)的調(diào)用,允許自定義環(huán)境變量和參數(shù)。
execl() 和 execv() 提供了簡化接口,execl() 使用可變參數(shù),execv() 使用參數(shù)數(shù)組。
execlp() 和 execvp() 可以根據(jù) PATH 環(huán)境變量搜索程序。
execle() 和 execvpe() 提供自定義環(huán)境變量的支持。
1
execve()
execve() 是最基礎(chǔ)的 exec 函數(shù),所有其他 exec 系列函數(shù)都是基于它的。它直接接受路徑名、參數(shù)數(shù)組和環(huán)境變量數(shù)組。
函數(shù)原型如下:
int execve(const char *filename, char *const argv[], char *const envp[]);
參數(shù)如下:
filename:要執(zhí)行的文件的路徑(絕對或相對路徑)。
argv[]:參數(shù)列表(傳遞給程序的命令行參數(shù))。第一個參數(shù)通常是程序本身的名稱。
envp[]:環(huán)境變量列表。
使用 execve() 執(zhí)行 /bin/ls,傳遞了參數(shù) -l 和環(huán)境變量 PATH。
#include <stdio.h>#include <stdlib.h>#include <unistd.h> int main(void) { char *argv[] = {"ls", "-l", NULL}; // 參數(shù)列表 char *envp[] = {"PATH=/bin", NULL}; // 環(huán)境變量 printf("執(zhí)行 ls 程序n"); if (execve("/bin/ls", argv, envp) == -1) { perror("execve error"); } return 0;}
2
execl()
execl() 是 execve() 的簡化版本,參數(shù)以可變長度的方式傳遞(列表形式)。最后一個參數(shù)必須是 (char *) NULL。
函數(shù)原型如下:
int execl(const char *path, const char *arg, ... /* (char *) NULL */);
參數(shù)如下:
path:可執(zhí)行文件的路徑。
arg:程序名稱后接任意數(shù)量的參數(shù),最后以 NULL 結(jié)束。
以下例子調(diào)用 execl(),通過可變參數(shù)傳遞給 ls 程序。
#include <stdio.h>#include <stdlib.h>#include <unistd.h> int main(void) { printf("使用 execl 執(zhí)行 ls 程序n"); execl("/bin/ls", "ls", "-l", (char *) NULL); // 傳遞可變長度參數(shù)列表 // 如果 exec 調(diào)用失敗,返回 -1 perror("execl error"); return 0;}
3
execlp()
execlp() 和 execl() 類似,但它不需要提供文件的完整路徑。它會在 PATH 環(huán)境變量指定的目錄中搜索可執(zhí)行文件。
函數(shù)原型如下:
int execlp(const char *file, const char *arg, ... /* (char *) NULL */);
參數(shù)如下:
file:要執(zhí)行的程序名(無需完整路徑)。
arg:程序名稱及其他參數(shù),最后以 NULL 結(jié)束。
以下例中,execlp() 會根據(jù) PATH 環(huán)境變量查找 ls 程序的路徑。
#include <stdio.h>#include <stdlib.h>#include <unistd.h> int main(void) { printf("使用 execlp 執(zhí)行 ls 程序n"); execlp("ls", "ls", "-l", (char *) NULL); // 使用環(huán)境變量中的路徑搜索 ls 程序 perror("execlp error"); return 0;}
4
execle()
execle() 類似于 execl(),但允許傳遞環(huán)境變量數(shù)組。
函數(shù)原型如下:
int execle(const char *path, const char *arg, ... /*, (char *) NULL, char * const envp[] */);
參數(shù)如下:
path:可執(zhí)行文件路徑。
arg:程序名稱及其他參數(shù),最后以 NULL 結(jié)束。
envp[]:環(huán)境變量數(shù)組。
以下例子中,execle() 將自定義的環(huán)境變量傳遞給 ls 程序。
#include <stdio.h>#include <stdlib.h>#include <unistd.h> int main(void) { char *envp[] = {"PATH=/bin", NULL}; // 設(shè)置環(huán)境變量 printf("使用 execle 執(zhí)行 ls 程序n"); execle("/bin/ls", "ls", "-l", (char *) NULL, envp); // 傳遞環(huán)境變量 perror("execle error"); return 0;}
5
execv()
execv() 是 execve() 的簡化版本,不需要傳遞環(huán)境變量,只需要路徑和參數(shù)數(shù)組。
函數(shù)原型如下:
int execv(const char *path, char *const argv[]);
參數(shù)如下:
path:可執(zhí)行文件的路徑。
argv[]:參數(shù)數(shù)組。
在該例中,execv() 使用參數(shù)數(shù)組執(zhí)行 ls。
#include <stdio.h>#include <stdlib.h>#include <unistd.h> int main(void) { char *argv[] = {"ls", "-l", NULL}; // 參數(shù)數(shù)組 printf("使用 execv 執(zhí)行 ls 程序n"); execv("/bin/ls", argv); // 傳遞參數(shù)數(shù)組 perror("execv error"); return 0;}
6
execvp()
execvp() 和 execv() 類似,但它會根據(jù) PATH 環(huán)境變量查找可執(zhí)行文件。
函數(shù)原型如下:
int execvp(const char *file, char *const argv[]);
參數(shù)如下:
file:可執(zhí)行文件的名稱。
argv[]:參數(shù)數(shù)組。
execvp() 不要求完整路徑,會自動在 PATH 中查找 ls。
#include <stdio.h>#include <stdlib.h>#include <unistd.h> int main(void) { char *argv[] = {"ls", "-l", NULL}; // 參數(shù)數(shù)組 printf("使用 execvp 執(zhí)行 ls 程序n"); execvp("ls", argv); // 根據(jù) PATH 搜索并執(zhí)行程序 perror("execvp error"); return 0;}
7
execvpe()
execvpe() 是 execvp() 的擴(kuò)展,允許傳遞自定義的環(huán)境變量。
函數(shù)原型如下:
int execvpe(const char *file, char *const argv[], char *const envp[]);
參數(shù)如下:
file:要執(zhí)行的程序名稱。
argv[]:參數(shù)數(shù)組。
envp[]:環(huán)境變量數(shù)組。
在以下示例中,execvpe() 使用自定義環(huán)境變量執(zhí)行程序。
#include <stdio.h>#include <stdlib.h>#include <unistd.h> int main(void) { char *argv[] = {"ls", "-l", NULL}; // 參數(shù)數(shù)組 char *envp[] = {"PATH=/bin", NULL}; // 環(huán)境變量 printf("使用 execvpe 執(zhí)行 ls 程序n"); execvpe("ls", argv, envp); // 使用 PATH 環(huán)境變量執(zhí)行程序 perror("execvpe error"); return 0;}
子進(jìn)程執(zhí)行新程序時,可以通過 exec 系列系統(tǒng)調(diào)用替換子進(jìn)程的內(nèi)存空間,執(zhí)行新的二進(jìn)制程序。exec 系列調(diào)用的不同變體提供了靈活的參數(shù)傳遞方式,適應(yīng)不同場景需求。通過合理使用 fork() 和 exec(),可以實(shí)現(xiàn)高效的多進(jìn)程編程,確保資源的有效利用和進(jìn)程的靈活控制。
*博客內(nèi)容為網(wǎng)友個人發(fā)布,僅代表博主個人觀點(diǎn),如有侵權(quán)請聯(lián)系工作人員刪除。