日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

进程间程序替换和minishell

發布時間:2024/4/11 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 进程间程序替换和minishell 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

進程間程序替換和minishell

文章目錄

  • 進程間程序替換和minishell
    • 一、進程間程序替換的原理
    • 二、exec函數族的用法及
    • 三、它們之間的聯系
    • 四、簡易的shell

一、進程間程序替換的原理

1.用fork創建子進程后執行的是和父進程相同的程序(但有可能執行不同的代碼分支),這樣就達不到創建進程的目的。

2.子進程往往要調用一種exec函數以執行另一個程序。當進程調用一種exec函數時,該進程的用戶空間代碼和數據完全被新程序替換,從新程序的啟動例程開始執行。

3.調用exec并不創建新進程,只是把進程的數據和代碼替換一下,讓其執行別的邏輯,所以調用exec前后該進程的pid并未改變。

如圖所示,有一個進程創建出的子進程本來是拷貝父進程的PCB,如果不進行分流,那么父子進程將會執行一摸一樣的邏輯,所以現在用exec函數族把子進程的數據段和代碼段替換掉,讓其執行別的邏輯

二、exec函數族的用法及

1.execl函數

int execl(const char *path, const char *arg, ...); 參數解釋
const char *path帶路徑的可執行程序(“/usr/bin/ls”)
const char *arg給可執行程序傳遞的參數,但必須是以可執行程序名作為第一個參數(ls -a -l)
可變參數列表,必須以NULL結尾,作為終止符

2.execlp函數

int execlp(const char *file, const char *arg, ...); 參數解釋
const char *file可執行程序的名稱,但是注意該可執行程序必須在PATH環境變量中可以被找到,否者就會替換失敗
const char *arg給可執行程序傳遞的參數,但必須是以可執行程序名作為第一個參數(ls -a -l)
可變參數列表,必須以NULL結尾,作為終止符

總結一下exec函數族中代p和不帶p的區別:如果帶p,說明進程運行時會去環境變量中尋找,第一個參數直接傳遞可執行程序名即可。對于不帶p,第一個參數必須指明可執行程序的路徑。

3.execle函數

int execle(const char *path, const char *arg, ...,char *const envp[]); 參數解釋
const char *path帶路徑的可執行程序
const char *arg給可執行程序傳遞的參數,但必須是以可執行程序名作為第一個參數(ls -a -l)
可變參數列表,必須以NULL結尾,作為終止符
char *const envp[]程序員自己組建環境變量,如果沒有則認為當前進程沒有環境變量,注意??環境變量也是以NULL結尾的

4.execv函數
總結一下帶e和不帶e的區別:如果函數帶e表示需要自己組裝環境變量。不帶e則不需要自己組裝環境變量

int execv(const char *path, char *const argv[]); 參數解釋
const char *path帶路徑的可執行程序
const char *argv[]給可執行程序傳遞的參數,但必須是以可執行程序名作為第一個參數,以NULL結尾

5.execvp函數

int execvp(const char *file, char *const argv[]); 參數解釋
const char *file可執行程序名,不帶路徑
char *const argv[]給可執行程序傳遞的參數,但必須是以可執行程序名作為第一個參數,以NULL結尾

6.execve函數

int execve(const char *path, char *const argv[], char *const envp[]); 參數解釋
const char *path帶路徑的可執行程序名
char *const argv[]給可執行程序傳遞的參數,但必須是以可執行程序名作為第一個參數,以NULL結尾
char *const envp[]程序員自己組建環境變量,如果沒有則認為當前進程沒有環境變量,注意??環境變量也是以NULL結尾的

用下面的方法方便理解記憶:

  • l(list) : 表示參數采用列表
  • v(vector) : 參數用數組
  • p(path) : 有p自動搜索環境變量PATH
  • e(env) : 表示自己維護環境變量
  • #include <unistd.h> int main() {char *const argv[] = {"ps", "-ef", NULL};char *const envp[] = {"PATH=/bin:/usr/bin", "TERM=console", NULL};execl("/bin/ps", "ps", "-ef", NULL);// 帶p的,可以使用環境變量PATH,無需寫全路徑execlp("ps", "ps", "-ef", NULL);// 帶e的,需要自己組裝環境變量execle("ps", "ps", "-ef", NULL, envp);execv("/bin/ps", argv);// 帶p的,可以使用環境變量PATH,無需寫全路徑execvp("ps", argv);// 帶e的,需要自己組裝環境變量execve("/bin/ps", argv, envp);exit(0); }

    三、它們之間的聯系

    1.聯系:

    從上圖可以看到所有的庫函數exec底層都是調用系統調用函數exeve函數

    2.對于它們返回值的理解:

  • 這些函數如果調用成功則加載新的程序從啟動代碼開始執行,不再返回。
  • 如果調用出錯則返回-1。
  • 所以exec函數只有出錯的返回值而沒有成功的返回值
  • 四、簡易的shell

    #include <stdio.h> #include <sys/wait.h> #include <ctype.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h>char g_command[1024];//該函數的功能是獲取命令行輸入的數據 int GetCommand() {//因為開始獲得的內存中的內容是不定的,所以使用前要先初始化memset(g_command,'\0',sizeof(g_command));//這里需要為'\0'留一個位置,不能把g_command全部用來讀取內容,否者就沒有結束標志,容易發生內存訪問越界if(fgets(g_command,sizeof(g_command)-1,stdin)==NULL){printf("fgets is error!\n");return -1;}//printf("g_command:%s\n",g_command);return 0; }//解析字符串 char** DealCommand(char* command) {if(command==NULL&&*command=='\0'){printf("dealcommand is error\n");return NULL;}//用來保存命令static char* argv[1024]={0};int argc=0;while(*command){//isspace函數用來去掉多余的空格//isspace的返回值:如果當前字符是空格返回1,否則返回0//注意'\0'在issapce函數中不算空格的,所以要進行判斷while(!isspace(*command)&&*command!='\0'){argv[argc]=command;argc++;//去找下一個空格while(!isspace(*command)&&*command!='\0'){command++;}*command='\0';}command++;}argv[argc]=NULL;//for(int i=0;i<argc;i++)//{// printf("%d:%s ",i,argv[i]);//}//printf("\n");return argv; }//進行程序替換 int exec() {char** argv=DealCommand(g_command);pid_t pid =fork();if(pid<0){printf("foek is error!\n");return -1;}else if(pid==0){//child//如果argc中為NULL,就直接返回if(argv[0]==NULL){exit(-1);}//進行替換,execvp第一個參數是可執行程序名,第二個參數是該可執行程序的參數組成的數組execvp(argv[0],argv);//execl("/usr/bin/ls","ls","-a",NULL);}else{//fatherwaitpid(pid,NULL,0);}return 0; }int main() {//循環讀數據while(1){printf("[dev@localhost dev]$ ");int ret = GetCommand();if(ret == -1){//如果讀取失敗,繼續循環讀取,不能直接break調continue;}//處理解析數據//char** argv = DealCommand(g_command);//進行替換//exec(argv);exec();}return 0; }

    總結

    以上是生活随笔為你收集整理的进程间程序替换和minishell的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。