第五週 mybash的實現

第五週 mybash的實現

1. 使用fork,exec,wait實現mybash
2. 寫出僞代碼,產品代碼和測試代碼
3. 發表知識理解,實現過程和問題解決的博客(包含代碼託管連接)

1. fork() 函數:

1. 一個進程,包括代碼、數據和分配給進程的資源。
2.  fork() 函數經過系統調用建立一個與原來進程幾乎徹底相同的進程,也就是兩個進程能夠作徹底相同的事,但若是初始參數或者傳入的變量不一樣,兩個進程也能夠作不一樣的事。
3. 一個進程調用fork() 函數後,系統先給新的進程分配資源,例如存儲數據和代碼的空間。而後把原來的進程的全部值都複製到新的新進程中,只有少數值與原來的進程的值不一樣。至關於克隆了一個本身。
在fork函數執行完畢後,若是建立新進程成功,則出現兩個進程,一個是子進程,一個是父進程。
fork調用的一個奇妙之處就是它僅僅被調用一次,卻可以返回兩次,它可能有三種不一樣的返回值:
1)在父進程中,fork返回新建立子進程的進程ID;
2)在子進程中,fork返回0;
3)若是出現錯誤,fork返回一個負值;

咱們能夠經過fork返回的值來判斷當前進程是子進程仍是父進程

有以下代碼:git

#include <unistd.h>  
#include <stdio.h>  
int main(void)  
{  
   int i=0;  
   printf("i son/pa ppid pid  fpid/n");  
   //ppid指當前進程的父進程pid  
   //pid指當前進程的pid,  
   //fpid指fork返回給當前進程的值  
   for(i=0;i<2;i++){  
       pid_t fpid=fork();  
       if(fpid==0)  
           printf("%d child  %4d %4d %4d/n",i,getppid(),getpid(),fpid);  
       else  
           printf("%d parent %4d %4d %4d/n",i,getppid(),getpid(),fpid);  
   }  
   return 0;  
}

運行結果以下:數組

分析:
第一次fork後,p3224(父進程)的變量爲i=0,fpid=3225(fork函數在父進程中返向子進程id)p3225(子進程)的變量爲i=0,fpid=0(fork函數在子進程中返回0)
第二步建立了兩個進程p3226,p3227,這兩個進程執行完printf函數後就結束了,由於這兩個進程沒法進入第三次循環,沒法fork,該執行return 0;了,其餘進程也是如此。bash

2. exec函數:

1. fork函數是用於建立一個子進程,該子進程幾乎是父進程的副本,而有時咱們但願子進程去執行另外的程序,exec函數族就提供了一個在進程中啓動另外一個程序執行的方法。
2. 它能夠根據指定的文件名或目錄名找到可執行文件,並用它來取代原調用進程的數據段、代碼段和堆棧段,在執行完以後,原調用進程的內容除了進程號外,其餘所有被新程序的內容替換了。
3. 這裏的可執行文件既能夠是二進制文件,也能夠是Linux下任何可執行腳本文件。

exec函數族使用注意點:
在使用exec函數族時,必定要加上錯誤判斷語句。由於exec很容易執行失敗,其中最多見的緣由有:
① 找不到文件或路徑,此時errno被設置爲ENOENT。
② 數組argv和envp忘記用NULL結束,此時errno被設置爲EFAULT。
③ 沒有對應可執行文件的運行權限,此時errno被設置爲EACCES。函數

在Linux中使用exec函數族主要有如下兩種狀況測試

若是一個進程想執行另外一個程序,那麼它就能夠調用fork函數新建一個進程,而後調用任何一個exec函數使子進程重生。
當進程認爲本身不能再爲系統和用戶作出任何貢獻時,就能夠調用任何exec 函數族讓本身重生。

execlp.c文件以下:ui

#include <stdio.h>
#include <unistd.h>
int main()
{
    if(fork()==0){
        if(execlp("/usr/bin/env","env",NULL)<0)
        {
            perror("execlp error!");
            return -1 ;
        }
    }
    return 0 ;
}

執行結果如圖:
3d

由執行結果看出,execlp函數使執行碼重生時繼承了Shell進程的全部環境變量,其餘三個不以e結尾的函數同理。code

3. wait()函數:

1. wait()會暫時中止目前進程的執行, 直到有信號來到或子進程結束. 
2. 若是在調用wait()時子進程已經結束, 則wait()會當即返回子進程結束狀態值. 
3. 子進程的結束狀態值會由參數status 返回, 而子進程的進程識別碼也會一快返回

4使用fork,exec,wait實現mybash:

部分代碼展現,所有代碼在碼雲裏blog

int main()
{
    char cmdline[MAX];
    
    while(1){
        printf("bsetixx@besrixx-VirtualBox:~/XINAN/mybash/$ ");
        fgets(cmdline,MAX,stdin);
        if(feof(stdin))
        {
            printf("error");
            exit(0);
        }
        eval(cmdline);
    }
}

void eval(char *cmdline)
{
    char *argv[MAX];
    char buf[MAX];
    int bg;
    pid_t pid;
    strcpy(buf,cmdline);
    bg = parseline(buf,argv);
    if(argv[0]==NULL)
        return;
    if(!builtin_command(argv)) 
    {   
    if((pid=fork()) == 0)
    {
        if(execvp(argv[0],argv) < 0) {
            printf("%s : Command not found.\n",argv[0]);
            exit(0);
        }
    }

    if(!bg){
        int status;
        if(waitpid(-1,&status,0) < 0) 
            printf("waitfg: waitpid error!");
    }
    else
        printf("%d %s",pid, cmdline);
    return;
    }
}

代碼提交截圖

代碼提交鏈接繼承

相關文章
相關標籤/搜索