wait函數和waitpid函數
1. 僵屍程序
- 說明
- 子程序結束但是沒有完全釋放記憶體(在核心中的task_struct沒有釋放),該程序就會成為僵屍程序
- 當僵屍程序的父程序結束後就會被init程序(1号程序)接管,最終被回收
- 僵屍程序的危害
- 如果你不處理僵屍程序的話,那麼保留的那段資訊就不會釋放,其程序号就會一定被占用,但是系統所能使用的程序号是有限的,如果大量的産生僵屍程序,将因為沒有可用的程序号而導緻系統不能産生新的程序
- 避免僵屍程序
- 讓僵屍程序的父程序來回收,父程序每隔一段時間來查詢子程序是否結束并被回收,調用wait或者waitpid函數,通知核心釋放僵屍程序
- 采用信号SIGCHLD通知處理,并在信号處理程式中調用wait函數
- 讓僵屍程序成為孤兒程序,并有init程序回收
2.避免僵屍程序方法一說明
- 頭檔案
#include <sys/types.h>
#include <sys/wait.h>
- 差別
- 在一個程序終止前,wait 使其調用者阻塞
- waitpid 函數有一個選擇項,可以使調用者不阻塞
- waitpid 等待一個指定的子程序,wait 等待所有的子程序,傳回任一子程序的終止狀态
- 參數
- status參數
- 為空時,代表任意狀态結束的子程序,若不為空,則代表指定狀态結束的子程序
- options參數
- WNOHANG:若由pid指定的子程序沒有退出則立即傳回,則waitpid不阻塞,此時傳回值為0
- WUNTRACED:若某實作支援作業控制,則由pid指定的任一子程序狀态已暫停,且其狀态自暫停以來還未報告過,則傳回其狀态
- 檢查 wait 和 waitpid 函數傳回終止狀态的宏(前面判斷,後面獲得狀态碼)
- WIFEXITED/WEXITSTATUS(status):若為正常終止子程序的傳回的狀态,則為真
- WIFSIGNALED/WTERMSIG(status):若為異常終止子程序的傳回的狀态,則為真(接到一個不能捕捉的信号)
- WIFSTOPED/WSTOPSIG(status):若為目前暫停子程序的傳回的狀态,則為真(如果目前程序在終止前暫停過,則獲得暫停的狀态碼)
- status參數
2. wait函數
- 原型:
pid_t wait(int *status)
- 傳回:成功傳回子程序ID,出錯傳回-1
- 作用:等待子程序退出并回收,防止僵屍程序産生
3. waitpid函數
- 原型:
pid_t waitpid(pid_t pid, int *status, int options)
- 傳回:成功傳回子程序ID,出錯傳回-1
- 功能:wait函數的非阻塞版本
- pid參數:
- pid == -1:等待任一子程序,與功能 wait 相等
- pid > 0:等待其程序ID與 pid 相等的子程序
- pid == 0:等待其組ID等于調用程序的組ID的任一子程序
- pid < -1:等待其組ID等于 pid 的絕對值的任一子程序
4. 示例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
void out_status(int status){
if(WIFEXITED(status)){
//正常終止
printf("normal exit: %d\n", WEXITSTATUS(status));
}
else if(WIFSIGNALED(status)){
//異常終止
printf("abnormal term: %d\n", WTERMSIG(status));
}
else if(WIFSTOPPED(status)){
//終止前暫停或者等待過
printf("stopped sig: %d\n", WSTOPSIG(status));
//kill -19 測試結果
}
else{
printf("unknow sig\n");
}
}
int main(void){
int status;
pid_t pid;
if((pid = fork()) < ){
perror("fork error");
exit();
}
else if(pid == ){
printf("pid: %d, ppid: %d\n", getpid(), getppid());
exit(); //子程序終止運作
}
//父程序阻塞,等待子程序結束并回收
wait(&status);
out_status(status);
printf("--------------------------\n");
if((pid = fork()) < ){
perror("fork error");
exit();
}
else if(pid == ){
printf("pid: %d, ppid: %d\n", getpid(), getppid());
int i = , j = ;
int k = i / j; //異常測試
printf("k: %d\n", k);
}
wait(&status);
out_status(status);
printf("--------------------------\n");
if((pid = fork()) < ){
perror("fork error");
exit();
}
else if(pid == ){
printf("pid: %d, ppid: %d\n", getpid(), getppid());
pause(); //暫停測試
}
do{
//暫停測試需要用waitpid來捕獲暫停的信号,并傳回
pid = waitpid(pid, &status, WNOHANG | WUNTRACED);
if(pid == ){
sleep();
}
}while(pid == );
out_status(status);
return ;
}
- 運作測試
- 運作程式
- 發送信号給程式
- 測試結果