程式等待和程式替換

ruo_bing發表於2018-08-30

終止程式

程式退出場景
  1. 程式碼執行完畢,結果正確退出
  2. 程式碼執行完畢,結果錯誤退出
  3. 程式碼異常終止
程式退出

1.正常退出
從main中return中退出;
呼叫void exit(int status)和 void _exit(int status) ,exit在任意位置呼叫都可以終止程式。

兩者區別:
這裡寫圖片描述

程式等待—–避免產生殭屍程式

殭屍程式的產生是因為子程式先行退出,父程式沒有關心子程式的退出狀態,一旦產生殭屍程式,kill -9 也不能殺死,並且我們也需要知道子程式執行任務的情況,是對是錯,還是異常,通過父程式等待的方式,我們可以瞭解情況,而且父程式回收子程式資源,獲取子程式的退出資訊,來避免產生殭屍程式。

以下是等待程式的兩個介面:

父程式呼叫wait獲取子程式的退出狀態

pid_t wait(int *status)

等待任意子程式的退出

對引數的理解:
引數statue所指空間存放子程式的退出狀態,不關心子程式是是什麼原因退出的,可以設定為NULL;
等待任意子程式的退出,父程式被阻塞,如果沒有子程式推遲,就一直等待,直到子程式退出,所以這種等待方式是阻塞式的;
等待成功,返回被等待的子程式的pid,等待失敗,返回-1

對阻塞的理解:
這裡寫圖片描述
pid_t waitpid(pid_t pid ,int *status,int options

可以等待任意子程式,也可以等待特定子程式

對引數的理解:
pid:pid = -1,功能與wait相同;pid >0時,等待其程式ID與pid相同的子程式
status:和wait的第二個引數功能是一樣的。
options:如果設定為0,那麼這個函式就是阻塞式等待,如果設定為WNOHANNG,就是非阻塞式等待(非阻塞式等待:父程式在等待子程式的同時也可以做其他的事情)

對引數status的詳細解釋

以下解釋適用於wait和waitpid兩個介面

int* status,是一個輸出型引數,由作業系統填充,如果不關心子程式的退出狀態資訊,就設定為NULL,否則作業系統會根據該引數,將子程式的退出資訊反饋給父程式。但它不能當做一個簡單的整數來看,應當做點陣圖來看,只看低16位位元位
這裡寫圖片描述

關於兩個巨集:WIFEXTEDHE (status)和 WEXITSTATUS(status)
這兩個巨集對於以上兩個介面都可以用
用這兩個巨集來檢查wait和waitpid所返回子程式的退出狀態;

如果WIFEXTEDHE (status)不是0,則子程式正常退出,可以利用 WEXITSTATUS(status)來檢視子程式的退出碼,例如子程式exit(3),那麼, WEXITSTATUS(status)的值就是3。需要強調的是,WEXITSTATUS(status)只能用來檢視正常退出的子程式的而退出碼

如果WIFEXTEDHE (status)是0,則子程式異常退出。

程式替換

用fork建立子程式後,人們往往希望它執行和父程式不一樣的程式,所以子程式
往往呼叫一種exec函式執行另外一個程式,本質來說要想子程式執行其他程式,就是將虛擬地址和頁表裡面的內容替換掉

實現程式替換的函式介面

六種exec開頭的替換函式:

int  execl(const char *path,const char *arg,...)   //第一個引數是要替換的程式的路徑(即要替換的程式在哪裡),接下來的引數都平鋪(一般用於linux指令),   ...代表不定引數
int execv(const char *path,char *const argv[])   //char *const argv[]引數為指標陣列
//兩者區別:引數如何賦予(平鋪,指標陣列)

程式碼如下:
要替換的而程式:
這裡寫圖片描述

替換執行程式碼:
這裡寫圖片描述
結果:
這裡寫圖片描述
後面跟p的

int execlp (const char *file,const char *arg,...)
int execvp(const char *file,char *const argv[])
//與第一組的區別就是不需要告訴作業系統的路徑,只需要告訴要替換的程式名稱即可,會自動到路徑下找(通常用於linux指令)

後面跟e 的

int  execle(const char *path,const char *arg,...char *const envp[])  
int execve(const char *path,char *const argv[],char *const envp[])
//與第一組的區別:帶e的是使用者自己組織環境變數,第一組的則是繼續父程式的環境變數

這些函式執行成功則開始執行新程式,不會在返回,失敗返回-1

//帶p的,不用跟路徑
eXeclp("test","test",NULL);
execvp("test",argv);

//帶e的,自己建立壞境變數
char *env[] = {"PATH = /user/bin/",  "HOME = JINFOCODMC",NULL};
execle("./test","test",NULL,env);
execve("./test",argv,env);

相關文章