Linux進程學習六

來源:互聯網
上載者:User

進程式控制制函數之exec()函數的學習

當我們看恐怖片時,經常會有這樣的情境:當一個人被鬼上身後,這個人的身體表面上還和以前一樣,但是他的靈魂和思想已經被這個鬼佔有了,因此它會控制這個人做他自己想做的事情--那麼在進程中也有這樣的情景。那麼是如何?的呢?現在我們來學習exec()函數族

一.exec()函數族

 

1. 首先我們在終端輸入命令:man exec 可以看到函數的原型:

#include <unistd.h>
int execl(const char *path, const char *arg, ...);
int execv(const char *path, char *const argv[]);
int execle(const char *path, const char *arg,..., char * const envp[]);
int execve(const char*pathname, const char *argv[], char *const envp[]);
int execlp(const char *file, const char *arg, ...);
int execvp(const char *file, char *const argv[]);
這些函數之間的第一個區別是前4個取路徑名做參數,後兩個則取檔案名稱做參數。
當指定filename做參數時:
a. 如果filename中包含/,則將其視為路徑名
b. 否則就按PATH環境變數搜尋可執行檔。
PATH=/bin:/usr/bin:/user/local/bin:.
最後的路徑首碼表示目前的目錄。零首碼耶表示目前的目錄(在name=value開始處可用:表示,在中間用::表示,在行尾用:表示)
第二個區別與參數表的傳遞有關(l表示list,v表示向量vector)。函數execl、execlp和execle要求將新程式的每個命令列參數都說明為一個單獨的參數,這中參數表以null 指標結尾。而execv、execve和execvp則要先構造一個指向各參數的指標數組,然後將該數組的地址作為這三個函數的地址。
第三個區別與向新程式傳遞環境表相關。函數execve和execle可以傳遞一個指向環境字串指標數組的指標。

Tiger-John總結:
1>.其中只有execve是真正意義上的系統調用,其它都是在此基礎上經過封裝的庫函數。
2>.exec函數族的作用是根據指定的檔案名稱找到可執行檔,並用它來取代調用進程的內容,換句話說,就是在調用進程內部執行一個可執行檔。這裡的可執行檔既可以是二進位檔案,也可以是任何Linux下可執行檔指令檔。

但是若為Shell指令碼時必須遵守以下的格式開頭:

第一行必須為: #!interpretername[arg]。其中interpretername可以時 shell或其他解譯器。例如,/bin/sh或/usr/bin/perl,arg是傳遞個解譯器的參數。

3>記憶方法:

l : 表示使用參數列表(list)

e:表示使用新的環境變數,不從當前繼承

p: 表示使用檔案名稱,並從PATH環境進行搜尋

4> exec()函數族成功後是不會傳回值的,因為進程的執行映像已經被替換,沒有接收傳回值的地方了。但是若有一個錯誤的事件,將會返回-1.這些錯誤通常是有檔案名稱或參數錯誤引起的。

2.exec()函數的功能:

1>exec()函數調用並沒有產生新進程,一個進程一旦調用exec函數,它本省就“死亡了”--就好比被鬼上身一樣,身體還是你的,但靈魂和思想已經被替換了--系統把程式碼片段替換成新的程式的代碼,廢棄原有的資料區段和堆棧段,並為新程式分配新的資料區段與堆棧段,唯一保留的就是進程ID。也就是說,對系統而言,還是同一個進程,不過執行的已經是另外一個程式了。

2>執行exec()函數後的進程除了保持了原來的進程ID,父進程ID,實際使用者ID和實際組ID之外,進程還保持了其他許多原有特徵,主要有

a.當前工作目錄

b.根目錄

c.建立檔案時使用的屏蔽字

d.進程訊號屏蔽字。

e. 未決警告

f.和進程相關的使用處理器的時間

g.控制終端

h.檔案鎖
Tiger-John說明:

1.此處要分清只有fork()或vfork()函數才能建立一個新進程,而exec()函數時不能建立進程的。

2.因此在使用exec()函數之前,先要使用fork()或vfork()建立子進程後,子進程調用exec()函數來執行另外一個程式。

 

 

3.exec()函數族的具體實現

1>當進程調用一種exec()函數時,該進程執行的程式完全替換為新程式,而新程式則從main函數開始執行。因為調用exec()並不建立新進程,所以前後的進程ID不變。函數exec()只是用一個全新的程式替換當前進程的本文、資料、堆和棧段。
2>無論是哪個exec()函數,都是將可執行程式的路徑,命令列參數和環境變數3個參數傳遞個可執行程式的main()函數。

3>具體介紹exec()函數族是如何main()函數需要的參數傳遞個它的。

a.execv()函數:execv()函數是通過路徑名方式調用可執行檔作為新的進程映像。它的argv參數用來提供給main()函數的argv參數。argv參數是一個以NULL結尾的字串數組

b.execve()函數:參數pathname時將要執行的程式的路徑名,參數argv,envp 與main()函數的argv,envp對應 。

c.execl()函數:次函數與execv函數用法類似。只是在傳遞argv 參數的時候,每個命令列參數都聲明為一個單獨的參數(參數中使用“......"說明參數的個數是不確定的),要注意的是這些參數要以一個null 指標作為結束。

d.execle()函數:該函數與execl函數用法類似,只是要顯示指定環境變數。環境變數位於命令列參數最後一個參數的後面,也就是位於null 指標之後。

e.execvp函數:該函數和execv函數用法類似,不同的是參數filename。該參數如果包含/,則將其視為路徑名,否則就按PATH環境變數搜尋可執行檔。

f.execlp()函數:該函數於execl函數類似,它們的區別和execvp與execv的區別一樣。

 

----------------------------------------------

通過以上學習,我們來編個程式來體驗下它的執行過程

4.函數執行個體

exec.c

1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<unistd.h>
  4 #include<stdlib.h>
  5 int main(int argc,char *argv[],char ** environ)
  6 {
  7         pid_t pid;
  8         int status;
  9         printf("Exec example!/n");
 10         pid = fork();
 11         if(pid < 0){
 12                 perror("Process creation failed/n");
 13                 exit(1);
 14         }
 15         else if(0 == pid){
 16                 printf("child process is running/n");
 17                 printf("My pid = %d ,parentpid = %d/n",getpid(),getpid());
 18                 printf("uid = %d,gid = %d/n",getuid(),getgid());
 19                 execve("processimage",argv,environ);
 20                 printf("process never go to here!/n");
 21                 exit(0);
 22         }
 23         else {
 24                 printf("Parent process is runnig/n");
 25         }
 26         wait(&status);
 27         exit(0);
 28 }

 

 

processimage.c

 1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<unistd.h>
  4
  5 int main(int argc,char * argv[],char ** environ)
  6 {
  7         int i;
  8
  9         printf("I am a process image!/n");
 10         printf("My pid =%d,parentpid = %d/n",getpid(),getppid());
 11         printf("uid = %d,gid = %d/n",getuid(),getpid());
 12
 13         for(i = 0;i<argc;i++){
 14                 printf("argv[%d]:%s/n",i,argv[i]);
 15         }
 16
 17 }

函數經過編譯:

think@ubuntu:~/work/process_thread/exec1$ gcc processimage.c -o processimage
think@ubuntu:~/work/process_thread/exec1$ gcc exec.c -o exec

think@ubuntu:~/work/process_thread/exec1$ ./exec test exec

函數執行結果:

Exec example!
Parent process is runnig
child process is running
My pid = 5949 ,parentpid = 5949
uid = 1000,gid = 1000
I am a process image!
My pid =5949,parentpid = 5948
uid = 1000,gid = 5949
argv[0]:./exec
argv[1]:test
argv[2]:exec
Tiger-John說明:

1.通過上面程式的執行,我們可以看到執行新程式的進程保持了原來進程的進程ID,父進程ID,實際使用者ID和實際組ID。

2. 當調用execve()函數後,原來的子進程的映像被替代,不再執行。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.