進程進程之間是有關係的,例如,父子進程、兄弟進程等。對於子進程而言,其退出時的狀態能夠由父進程獲得。函數
Linux內核爲每一個終止的子進程保存必定量的信息,這些信息包括進程ID、進程終止狀態以及改進程的一些統計信息等。這些信息能夠由父進程獲得並作一些處理。性能
Linux下使用wait()函數獲得子進程的結束信息,其原型以下:優化
#include <sys/wait.h> pid_t wait(int *statloc);
調用wait()函數的進程會阻塞,直到該進程的任意一個子進程結束,wait()函數會獲得結束的子進程的信息並返回該子進程的進程ID,結束信息保存在參數statloc所指向的內存空間中。若是改進程沒有子進程,則當即出錯返回,返回值爲-1;若是在調用wait()函數時已經有若干個子進程結束運行了,則wait()函數當即返回,可是具體獲得的是哪一個子進程的信息則是不肯定的,須要根據子進程的ID來判斷。spa
wait()函數的參數用來保存子進程的返回信息,內核會將取得的子進程結束信息保存在該指針所指向的空間。若是該指針爲NULL,則表示用戶堆返回信息不關心。指針
返回信息是一個整數,不一樣的位表明不一樣的信息,它們是進程正常結束狀態、終止進程的信號編號和暫停進程的信號編號。Linux提供了專門的宏,來判斷哪些狀態有效而且取得相應的狀態值:code
狀態 | 判斷宏 | 取值宏 |
進程正常結束 | WIFEXITED(status) | WEXITSTATUS(status) |
進程異常結束 | WIFSIGNALED(status) | WTERMSIG(status) |
進程暫停 | WIFSTOPPED(status) | WSTOPSIG(status) |
例如,當一個進程正常退出時,改進程的父進程獲得其結束信息,需判斷:若是WIFEXITED(status)值爲真,那麼說明該進程是正常退出的,WEXITSTATUS(status)使用返回信息中進程結束狀態便可。orm
下面例子演示瞭如何使用wait函數取得子進程的結束狀態:進程
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> int main(void) { pid_t pid; int num, status; pid = fork(); if(pid < 0){ perror("fail to fork\n"); exit(1); }else if(pid == 0){ //第一個子進程 printf("the first, exit normally\n"); exit(0); }else { if(wait(&status) == -1){ //父進程等待子進程的退出 perror("fail to wait\n"); exit(1); } if(WIFEXITED(status) == 1) { //獲得正常退出的退出狀態,exit()函數的參數 printf("the status of first is : %d\n", WEXITSTATUS(status)); } } pid = fork(); if(pid < 0){ perror("fail to fork\n"); exit(1); }else if(pid == 0){ //第二個子進程 printf("the second, exit abnormally\n"); num = 1/0; //除以0,會產生SIGFPE異常信號 }else{ if(wait(&status) == -1){ //父進程等待子進程退出 perror("fail to wait\n"); exit(1); } if(WIFSIGNALED(status) == 1){ //獲得終止子進程的信號的值 printf("the terminated signal is : %d\n", WTERMSIG(status)); } } return 0; }
運行結果:內存
wait()函數能夠等待子進程的退出,而且得到其退出狀態信息。可是wait()函數只能等待第一個結束的子進程,若是須要指定等待一個子進程,則須要使用以下代碼實現:ci
int status; //保存進程的狀態信息 //pid中保存的是須要的獲得的結束信息的進程ID //若是獲得結束狀態信息的進程不是所須要的進程,則循環取子進程的結束狀態 while(pid != wait(&status));
Linux下提供waitpid()函數,用以等待一個指定的子進程:
#include <sys/wait.h> pid_t waitpid(pid_t pid, int *statloc, int options);
waitpid()函數的第一個參數指定要等待的子進程的進程ID,pid參數的做用以下:
pid值 | 等待的做用 |
-1 | 等待任意子進程 |
>0 | 等待進程ID和pid相等的子進程 |
0 | 等待組ID和pid相等的子進程 |
<-1 | 等待組ID等於pid絕對值的組內任意子進程 |
waitpid()函數的第二個參數的意義和wait()函數相同,第三個是控制選項,該選項有3中狀況,其中2種和做業控制有關:
選項 | 選項說明 |
WCONTINUED | 當子進程在暫停後繼續執行,且其狀態還沒有報告,則返回其狀態 |
WNOHANG | 當所等待進程還沒有結束運行時不阻塞,waitpid()函數直接返回 |
WUNTRACED | 當子進程暫停時,而且其狀態自暫停以來還未報告過,則返回其狀態 |
該參數能夠是0,也能夠由上面所述的3種選項「或」獲得。
下面的實例演示了使用WNOHANG選項非阻塞等待一個子進程:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> int main(int argc, char *argv[]) { pid_t pid; pid = fork(); if(pid < 0){ printf("fail to fork\n"); exit(1); } else if(pid == 0) { //子進程 printf("the child\n"); sleep(3); exit(0); } else { printf("the parent\n"); if(waitpid(pid, NULL, WNOHANG) == 0) //非阻塞等待子進程 printf("the child is not available now\n"); } printf("no waiting, parent done\n"); return 0; }
運行結果:
從上面的程序中能夠看出父進程並無阻塞在waitpid()函數上。
waitpid()函數和wait()函數的區別有一下3點:
wait3()函數和wait4()函數基本等同於wait()函數和waitpid()函數,不一樣的是wait3()和wait4()函數除了wait()和waitpid()函數的功能外,還可以獲得更詳細的信息。這些信息CPU使用時間等,其保存在內核中,病經過參數rusage結構返回給用戶,函數原型以下:
#include <sys/types.h> #include <sys/wait.h> #include <sys/time.h> #include <sys/source.h> pid_t wait3(int *statloc, int options, struct rusage *rusage); pid_t wait4(pid_t pid, int *statloc, int options, struct rusage *rusage);
參數rusage是一個統計資源結構的指針,其結構聲明以下:
struct rusage { struct timeval ru_utime; //用戶CPU時間 struct timeval ru_stime; //系統CPU時間 long int ru_maxrss; //最大rss數量 long int ru_ixrss; //與其餘進程共用代碼段數量 long int ru_idrss; //數據段大小 long int ru_isrss; //棧大小 long int ru_minflt; //軟頁面錯誤 long int ru_majflt; //硬頁面錯誤 long int ru_nswap; //換頁次數 long int ru_inblock; //從文件系統讀次數 long int ru_oublock; //向文件系統寫次數 long int ru_msgsnd; //發送消息數 long int ru_msgrcv; //接受消息數 long int ru_nsignals; //收到信號數 long int ru_nvcsw; //主動換頁次數 long int ru_nivcsw; //被動換頁次數 };
讀者使用上面結構得出須要的進程信息,例如用戶CPU時間加上系統CPU時間能夠獲得程序佔用CPU的時間,再用程序運行總時間減去該時間,就能夠獲得程序運行時的I/O時間。這樣就能夠知道程序的性能瓶頸在自己的計算流程上仍是在I/O上,由此能夠優化程序。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> #include <sys/types.h> #include <sys/resource.h> int main(int argc, char *argv[]) { pid_t pid; struct rusage rusage; pid = fork(); if(pid < 0){ printf("fail to fork\n"); exit(0); } else if(pid == 0){ printf("the child\n"); exit(0); } else { printf("the parent\n"); } if(wait3(NULL, 0, &rusage) == -1) { //獲得改進程的詳細信息 perror("fail to wait"); exit(1); } printf("utime is %d\n", rusage.ru_utime); //打印用戶CPU時間 printf("stime is %d\n", rusage.ru_stime); //打印系統CPU時間 printf("maxrss is %ld\n", rusage.ru_maxrss); //打印最大rss數量 printf("ixrss is %ld\n", rusage.ru_ixrss); //打印與其餘進程共用代碼段的數量 return 0; }
運行結果: