類比shell ( 進程函數:fork(),execvp(),wait() )

來源:互聯網
上載者:User

標籤:shell   編程   linux   unix   核心   

      shell是一個管理進程和運行進程的程式,下面我們就通過類比一個shell程式這個執行個體來更好地認識認識在Linux/Unix系統中,進程的建立和結束,以及父子進程之間的一些關係。接下來先貼上原始碼的中命令的讀取部分:

  numargs=0;  while(numargs<MAXARGS){   printf("Arg[%d]?",numargs);   if(fgets(argbuf,ARGLEN,stdin)&&*argbuf!='\n')     arglist[numargs++]=makestring(argbuf);   else{    if(numargs>0){      arglist[numargs]=NULL;      execute(arglist);      numargs=0;    }   }  }

       這一段代碼用於讀取使用者輸入的命令,儲存在arglist這個字元指標的數組中。因為進程間的通訊的參數類型為字串,所以我們選擇指向字串的指標構成的數組作為傳遞的參數,並且注意要將最後一個指標置NULL。當命令讀取完畢完畢之後,即調用execute函數並且將arglist數組傳遞給它,進行關於子進程的一些操作。接下來,我們來看看execute函數具體的實現情況。

execute(char *arglist[]){  int pid,exitstatus;  pid=fork();//建立子進程  switch(pid){   case -1:     perror("fork failed");     exit(1);   case 0:     execvp(arglist[0],arglist);//替換子進程     perror("execvp failed");     exit(1);   default:     while(wait(&exitstatus)!=pid);//父進程等待     printf("child exited with status %d,%d\n",exitstatus>>8,exitstatus&0377);  }}

    在execute函數中最先調用fork()函數,那fork()函數做了些什麼呢?其實fork()函數建立了和當前進程基本一模一樣的一個子進程。當控制轉到核心中的fork代碼之後,核心先分配新的記憶體塊和核心資料結構,然後將原來的進程複製到新的進程中去。最後向運行進程中添加新的進程並且控制重新返回到進程中。開始可能覺得挺奇怪的,搞個基本差不多的進程幹什嗎?其實看了後面的內容你就會知道,只要調用個execvp函數,子進程就變得完全不一樣啦。好,現在我們就有兩個進程了,並且它們的代碼相同,都運行到

  pid=fork();//建立子進程
       這一步,那我們怎麼判斷哪個是父進程,哪個是子進程呢?其實在父進程中fork函數的返回值是子進程的進程ID,而在子進程中,fork返回的是0,所以我們通過fork的返回值就能判斷父子進程了。下面進入switch部分,若fork返回-1,說明建立子進程失敗,若是在子進程中,則調用execvp函數(其實execvp不是系統調用,而是一個庫函數,它通過調用execve來調用核心服務)來執行指明的程式。那我們就來看看execvp這個函數幹了些什嗎?

result=execvp(const char*file,const char*argv[])
      其中第一個參數指明了要執行的進程,如:“ls”,"ps"等等命令,而第二個參數則為指向要執行的命令及相關參數的字串指標。通過調用execvp我們就能在一個進程中,執行像"ls"這樣另外一個進程了。但是有一個問題需要注意,那就是execvp會清除當前進程,並載入由file指定的進程。也就是說,比如當"ls"執行完之後,execvp下面的那句perror是不會執行的,因為它早就被“ls”的代碼替換掉了。這其實也就是我們為什麼要建立子進程的原因。如果在父進程中調用execvp的話,我們做的這個shell程式就只能調用一條命令了。

      那我們就要想了,父進程這個時候在幹嘛呢?其實在fork之後,父子進程是並存執行的,而我們想要的效果是父進程先等等,等子進程結束之後再繼續執行。接下來的wait函數就滿足了我們的願望啦!

pid=wait(&status)
      wait函數主要做兩件事,首先wait暫停調用它的進程直到子進程結束,然後wait通過status取得子進程結束時傳給exit的值。wait返回結束進程的PID,如果進程沒有子進程或沒有得到終止狀態值,則返回-1。

      這樣通過不斷地建立子進程,用想要執行的程式代替子進程並且讓父進程等待,最後執行完畢,回到父進程,我們也就類比了一個shell程式啦。最後來說說,結束進程的函數exit。exit的話,它會先重新整理所有的流,調用一些函數,執行當前系統定義的其他和exit相關的操作。最後,調用_exit這個核心操作,來進行釋放記憶體,關閉相關檔案這些善後工作。

    就這樣,通過幾個函數的調用,我們就幫一個進程走過了它短暫的一生。其實仔細想想也不是那麼複雜嘛,哢哢哢~

 


參考文獻:《Understanding Unix/Linux Programming ----A Guide to Theory and Practice》                                                                      

類比shell ( 進程函數:fork(),execvp(),wait() )

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.