今天:進(jìn)程結(jié)束 -fork() /exit退出進(jìn)程/wait()父進(jìn)程等待子進(jìn)程/vfork()Unix/Linux 信號
break是用來退循環(huán)澎蛛,return退函數(shù)氯檐,exit()退進(jìn)程
程序員退出進(jìn)程的方式:
1.正常退出
a.在主函數(shù)中執(zhí)行了return語句(特殊的,因?yàn)橹粚χ骱瘮?shù)有效)
b._exit()或_Exit()函數(shù)退出進(jìn)程(立即退出)
c. exit()退出進(jìn)行(通用方式)
d.最后一個線程結(jié)束
2.非正常退出
a.被信號干掉了寂玲,比如:ctrl+cb.最后一個線程被取消
exit()/_exit()/_Exit()_exit(int) /_EXIT(int)這兩個在底層是一樣的塔插,_Exit()調(diào)用了_exit()
exit()函數(shù)會退出進(jìn)程,但不一定是馬上退出拓哟,允許通過atexit()函數(shù)注冊一些其他的函數(shù)想许,在退出前會先執(zhí)行注冊過的函數(shù)。
_exit()函數(shù)會立即退出,退出只做三件事:
1.關(guān)閉文件描述符
2.讓所有的子進(jìn)程變成孤兒進(jìn)程
3.發(fā)退出信號給父進(jìn)程如果沒有特殊需求流纹,退出進(jìn)程用exit()即可糜烹。
wait()和waitpid()
wait()和waitpid()可以讓父進(jìn)程等待子進(jìn)程的結(jié)束,可以取得子進(jìn)程結(jié)束的方式(正常退出還是非正常退出)和退出碼
wait()必須等待任意一個子進(jìn)程的結(jié)束漱凝,只要有子進(jìn)程結(jié)束疮蹦,那么wait()就返回,如果沒有子進(jìn)程結(jié)束茸炒,父進(jìn)程繼續(xù)等待愕乎。waitpid()可以等待多種方式的子進(jìn)程,也可以一個都不等待壁公,因此更靈活感论。
wait()和waitpid()能回收僵尸子進(jìn)程的資源。
pid_t wait(int* status)
功能:等待任意一個子進(jìn)程的結(jié)束紊册,并取得退出狀態(tài)和退出碼參數(shù):
status是傳出參數(shù)比肄,返回子進(jìn)程的退出狀態(tài)和退出碼返回值:返回結(jié)束子進(jìn)程的PID
宏函數(shù)被用于判斷子進(jìn)程的退出狀態(tài)和獲取退出碼WIFEXITED(status) 判斷是否正常退出WEXITSTATUS(status)獲取退出碼(只有正常退出才有效)
5 int main()
6{
7 pid_t pid = fork();
8 if(pid==0){//子進(jìn)程分支
9 sleep(2);
10 printf("子進(jìn)程%d開始運(yùn)行\(zhòng)n",getpid());
11 sleep(2);
12 printf("子進(jìn)程%d結(jié)束\n",getpid());
13 exit(10);
14 }
15 int status;
16 pid_t wpid= wait(&status);
17 if(WIFEXITED(status))
18 {
19? ? printf("子進(jìn)程%d結(jié)束,退出碼%d\n",wpid,WEXITSTATUS(status));
20 }
21 printf("父進(jìn)程結(jié)束\n");
22
運(yùn)行結(jié)果:
子進(jìn)程14587開始運(yùn)行
子進(jìn)程14587結(jié)束
子進(jìn)程14587結(jié)束湿硝,退出碼10
父進(jìn)程結(jié)束
pid_t waitpid(pid_t pid,int* status,int options)
功能:等待子進(jìn)程的結(jié)束薪前,但比wait()更靈活(可以不等)
第一個參數(shù):pid是等待哪個/哪些子進(jìn)程润努,包括:
-1 等待任意一個子進(jìn)程的結(jié)束
>0 等待特定的一個子進(jìn)程(進(jìn)程ID=pid)
0? 等待和父進(jìn)程一個進(jìn)程組的子進(jìn)程(本組)
<-1等待指定進(jìn)程組的子進(jìn)程(進(jìn)程組ID=|pid|)
第二個參數(shù):status和wait()中的一樣
第三個參數(shù):option可以設(shè)置等待或是不等待关斜,默認(rèn)0為等待,宏WNOHANG可以代表不等待铺浇。
返回:有子進(jìn)程結(jié)束返回結(jié)束子進(jìn)程的PID痢畜,如果不等待并且沒有子進(jìn)程結(jié)束返回0,失敗返回-1鳍侣。
int main()
7 {
8? ? pid_t pid1,pid2;//一父二子需要判斷
9 pid1 = fork();
10
11 if(pid1>0)pid2 = fork();
12? if(pid1==0){//進(jìn)程1
13? sleep(1);
14? printf("子進(jìn)程-%d結(jié)束\n",getpid());
15? exit(20);
16? }
17 if(pid2==0) {
18 sleep(3);
19 printf("子進(jìn)程-%d結(jié)束\n",getpid());
20 exit(20);
21 }
22 int status;
23 pid_t wpid = waitpid(pid1,&status,0);
24 if(WIFEXITED(status))
25 {
26 printf("子線程%d,退出碼%d\n",wpid,WEXITSTATUS(status));
27 }
28 }
vfork() +execl()創(chuàng)建子進(jìn)程
fork()函數(shù)從語法上和fork()沒有任何區(qū)別丁稀,區(qū)別在于fork()不會復(fù)制父進(jìn)程的任何資源。子進(jìn)程會占用父進(jìn)程的資源繼續(xù)運(yùn)行倚聚,而父進(jìn)程會阻塞线衫,停止運(yùn)行。父進(jìn)程的阻塞有兩種方法可以解除
1.子進(jìn)程運(yùn)行結(jié)束惑折,把資源還給父進(jìn)程
2.子進(jìn)程調(diào)用了execl()授账,啟動了一個全新的程序,也把原來的資源還給父進(jìn)程(并行的方式)惨驶。
第二種方法更有意義更常用白热,第一種方法沒有實(shí)際意義。
vfork()會創(chuàng)建一個新的子進(jìn)程粗卜,可以確保子進(jìn)程先運(yùn)行屋确。
vfork()創(chuàng)建的子進(jìn)程必須用exit()退出,return語句退出會有問題。
vford()函數(shù)能創(chuàng)建子進(jìn)程攻臀,但是不能提供代碼和數(shù)據(jù)焕数,execl()函數(shù)不能創(chuàng)建子進(jìn)程,但可以提供進(jìn)程運(yùn)行的代碼和數(shù)據(jù)刨啸。
execl()函數(shù)不會創(chuàng)建新的進(jìn)程百匆,進(jìn)程PID不變,用一個新的程序替換掉當(dāng)前進(jìn)程執(zhí)行的程序呜投。
int execl(char* path,char* cmd,...)
功能:啟動一個全新的程序加匈,當(dāng)前程序?qū)⒈惶鎿Q,但不會建立新進(jìn)程
參數(shù):path就是新程序的路徑仑荐,包括文件名雕拼,不能出錯
cmd就是運(yùn)行程序的命令,比如:a.out
...可以包括命令的參數(shù)/命令的選項(xiàng)粘招,最后以NULL結(jié)束
返回:成功則啟動新程序啥寇,沒有任何返回值
失敗就無法啟動新程序,返回-1
關(guān)于進(jìn)程必須會寫代碼:
fork()
vfork()和execl()