linux進程控制 exec系統調用

    linux進程控制-exec系列 說是exec系統調用,實際上在Linux中,並不存在一個exec()的函數形式,exec指的是一組函數,一共有6個,分別是:

#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 execve(const char *path, char *const argv[], char *const envp[]);

       其中只有execve是真正意義上的系統調用,其它都是在此基礎上經過包裝的庫函數。exec函數族的作用是根據指定的文件名找到可執行文件,並用它來取代調用進程的內容,換句話說,就是在調用進程內部執行一個可執行文件。這裏的可執行文件既可以是二進制文件,也可以是任何Linux下可執行的腳本文件。


       與 一般情況不同,exec函數族的函數執行成功後不會返回,因爲調用進程的實體,包括代碼段,數據段和堆棧等都已經被新的內容取代,只留下進程ID等一些表 面上的信息仍保持原樣,頗有些神似"三十六計"中的"金蟬脫殼"。看上去還是舊的軀殼,卻已經注入了新的靈魂。只有調用失敗了,它們纔會返回一個-1,從 原程序的調用點接着往下執行。


       現在我們應該明白了,Linux下是如何執行新程序的,每當有進程認爲自己不能爲系統 和擁護做出任何貢獻了,他就可以發揮最後一點餘熱,調用任何一個exec,讓自己以新的面貌重生;或者,更普遍的情況是,如果一個進程想執行另一個程序, 它就可以fork出一個新進程,然後調用任何一個exec,這樣看起來就好像通過執行應用程序而產生了一個新進程一樣。


       事 實上第二種情況被應用得如此普遍,以至於Linux專門爲其作了優化,我們已經知道,fork會將調用進程的所有內容原封不動的拷貝到新產生的子進程中 去,這些拷貝的動作很消耗時間,而如果fork完之後我們馬上就調用exec,這些辛辛苦苦拷貝來的東西又會被立刻抹掉,這看起來非常不划算,於是人們設 計了一種"寫時拷貝(copy-on-write)"技術,使得fork結束後並不立刻複製父進程的內容,而是到了真正實用的時候才複製,這樣如果下一條 語句是exec,它就不會白白作無用功了,也就提高了效率。

/* exec.c */
#include <unistd.h>
int main(int argc, char *argv[])
{
   char *envp[]={
       "PATH=/tmp",
       "USER=lei",
       "STATUS=testing",
       NULL
   };

  char * argv_execv[] = { "echo", "excuted by execv", NULL };
  char *argv_execvp[] = { "echo", "executed by execvp", NULL };
  char *argv_execve[] = { "env",  NULL };
 
  if(fork()==0) {
      if(execl("/bin/echo", "echo", "executed by execl", NULL)<0) {
           perror("Err on execl");
      }
  }

  if(fork()==0) {
      if(execlp("echo", "echo", "executed by execlp", NULL)<0) {
           perror("Err on execlp");
      }
  }

  if(fork()==0) {
      if(execle("/usr/bin/env", "env", NULL, envp)<0) {
           perror("Err on execle");
      }
  }

  if(fork()==0) {
      if(execv("/bin/echo", argv_execv)<0) {
           perror("Err on execv");
      }
  }

  if(fork()==0) {
      if(execvp("echo", argv_execvp)<0) {}
           perror("Err on execvp");
      }
  }

  if(fork()==0) {
      if(execve("/usr/bin/env", argv_execve, envp)<0) {
           perror("Err on execve");
      }
  }
  return 0;
}

       程序裏調用了2個Linux常用的系統命令,echo和env。echo會把後面跟的命令行參數原封不動的打印出來,env用來列出所有環境變量。由於各個子進程執行的順序無法控制,所以有可能出現一個比較混亂的輸出--各子進程打印的結果交雜在一起,而不是嚴格按照程序中列出的次序。

      編譯並運行:

$ cc exec.c -o exec
$ ./exec

executed by execl
PATH=/tmp
USER=lei
STATUS=testing
executed by execlp
excuted by execv
executed by execvp
PATH=/tmp
USER=lei
STATUS=testing

 

發佈了25 篇原創文章 · 獲贊 42 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章