【linux】程序建立、等待、終止
建立程序—fork函式
函式原型:pid_t fork(void);
返回值:子程序返回0;父程序返回子程序pid,失敗返回-1(失敗的原因:1記憶體不夠;2系統程序數量太多);
注意:fork之前,父程序獨立執行,fork之後,父子兩個執行流分別執行。但是父子程序誰先執行是由系統排程決定。
寫實拷貝:父程序建立子程序後,子程序室父程序的副本;父子程式碼共享,父子不寫入時,資料也是共享。當任意一方試圖寫入時,便以寫實拷貝的方式各自建立一份副本。
程式碼:
1 #include<stdio.h>
2 #include<unistd.h>
3
4 int main()
5 {
6 pid_t pid = fork();
7 if(pid>0){
8 sleep(3);
9 printf("I am father:%d\n",getpid());
10 }else if(pid==0){
11 printf("I am child:%d\n",getpid());
12 sleep(1);
13 }else{
14 perror("fork");
15 }
16 return 0;
17 }
vfork函式:也是建立程序,用法跟fork相似;
不同的是:
1、vfork一個子程序,父子程序共享地址空間,而fork的子程序具有獨立的地址空間。
2、vfork保證子程序先執行,直到呼叫exec或者exit之後父程序才執行。
程式碼:
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<stdlib.h>
4 int flag = 100;//設定一個全域性變數100
5 int main()
6 {
7 pid_t pid = vfork();
8 if(pid>0){
9 sleep(2);
10 flag = 10;//父程序把flag變為10;
11 printf("father:%d;flag = %d\n",getpid(),flag);
12 exit(0);
13 }else if(pid==0){
14 flag = 0; //子程序把flag變為0; printf("child:%d,father_id=%d,flag=%d\n",getpid(),getppid(),flag);
16 sleep(5);
17 }else{
18 perror("fork");
19 }
20 return 0;
21 }
結果:
我們看到子程序改變了父程序的的值,因為子程序實在父程序的地址空間執行。)
程序等待—wait和waitpid
程序等待必要性:
1、子程序退出,如果父程序不管不顧,就可能造成殭屍程序的問題,造成記憶體洩露。
2、父程序需要知道子程序的退出狀態,完成的任務結果如何。
3、父程序通過程序等待的方式,回收子程序資源,獲取子程序退出狀態。
函式原型:pid_t wait(int *status)
返回值:成功返回被等待程序的pid;失敗返回-1;
引數:輸出型引數,獲取子程序的退出狀態,不關心可以設定為NULL;
status&0x7f==0:表示程式碼執行完了,正常退出;
status&0x7f!=0:表示異常退出,具體值表示使該程序退出的訊號的編碼。
status>>8 & 0xff的值表示子程序的退出碼。
呼叫wait函式會發生什麼?
1. 如果有子程序在執行,父程序進入阻塞狀態(可以理解為什麼事情都沒有做,一直在檢測子程序是否在執行)
2.如果父程序在呼叫wait前子程序已經終止,wait可立即獲得子程序的終止狀態(退出碼,退出資訊),子程序的終止狀態是體現在status引數上的,另外wait還會返回所終止的子程序的識別符號。
3.如果當前沒有子程序,則會出錯返回-1。
4.如果有一個子程序終止,那麼wait便返回。
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<sys/types.h>
4 #include<sys/wait.h>
5
6 int main()
7 {
8 int ret=fork();
9 if(ret>0){
10 int status=0;
11 int wait_id = wait(&status);
12 if(wait_id>0){
13 printf("child has success dead!,id=%d\n",wait_id);
14 }else{
15 printf("child has false dead!,%d\n",wait_id);
16 }
17 }else if(ret==0){
18 printf("I am child,id=%d\n",getpid());
19 sleep(5);
20 exit(0);
21 }else{
22 perror("fork");
23 }
24 return 0;
25 }
waitpid函式:也是建立程序,用法跟wait相似;
函式原型:pid_t waitpid(pid_t pid,int *status,int options)
pid:檢測子程序的pid
status:子程序的終止狀態,如果不是空指標,則終止程序的終止資訊就存放在它所指向的單元內。不關心終止狀態可以將status製成NULL。
options:指定引數,預設情況下waitpid與wait做的事情都是一樣的,為阻塞式監測子程序終止狀態;當options=WNOHANG時,此時為非阻塞方式,就是監測時如果子程序沒有終止,呼叫者可以做其他事情,另外還有兩個引數分別為WCONTINUED和WUNTRACED,這兩個引數是跟作業控制有關的。
結果:
非阻塞等待:
結果:
WNOHANHG:若子程序沒有結果,waipid返回0,不予等待,若正常結束,則返回該子程序的pid。
WIFEXITED(status):表示若為正常終止子程序返回的狀態,則為真(檢視程序是否是正常退出),這個巨集用來指出子程序是否為正常退出的,如果是,它會返回一個非零值;
WEXITSTATUS(status):若WIFEXITED非零,提取子程序的退出碼(檢視程序退出碼)。
程序終止—_exit()和exit()
檢視程序退出碼: echo $?
#include<unistd.h>
void _exit(int status)
引數:status定義了程式的終止狀態,父程序通過wait獲取該值。
#include<unistd.h>
void exit(int statsu)
_exit()—系統呼叫 exit()— 庫函式
exit()做的三件事:
1,執行使用者通過atexit或者on_exit定義的清理函式
2,關閉所有開啟流,所有的快取資料均被寫入。
3,呼叫_exit;
思考題:vfork建立的子程序, 直接return為什麼會出現崩潰?
結束子程序的呼叫是exit()而不是return,如果你在vfork中return了,那麼,這就意味main()函式return了,注意因為函式棧父子程序共享,所以整個程式的棧就出現問題了。