天天看點

wait函數和waitpid函數

wait函數和waitpid函數

1. 僵屍程序

  1. 說明
    1. 子程序結束但是沒有完全釋放記憶體(在核心中的task_struct沒有釋放),該程序就會成為僵屍程序
    2. 當僵屍程序的父程序結束後就會被init程序(1号程序)接管,最終被回收
  2. 僵屍程序的危害
    1. 如果你不處理僵屍程序的話,那麼保留的那段資訊就不會釋放,其程序号就會一定被占用,但是系統所能使用的程序号是有限的,如果大量的産生僵屍程序,将因為沒有可用的程序号而導緻系統不能産生新的程序
  3. 避免僵屍程序
    1. 讓僵屍程序的父程序來回收,父程序每隔一段時間來查詢子程序是否結束并被回收,調用wait或者waitpid函數,通知核心釋放僵屍程序
    2. 采用信号SIGCHLD通知處理,并在信号處理程式中調用wait函數
    3. 讓僵屍程序成為孤兒程序,并有init程序回收

2.避免僵屍程序方法一說明

  • 頭檔案
#include <sys/types.h>
    #include <sys/wait.h>
           
  • 差別
    1. 在一個程序終止前,wait 使其調用者阻塞
    2. waitpid 函數有一個選擇項,可以使調用者不阻塞
    3. waitpid 等待一個指定的子程序,wait 等待所有的子程序,傳回任一子程序的終止狀态
  • 參數
    1. status參數
      1. 為空時,代表任意狀态結束的子程序,若不為空,則代表指定狀态結束的子程序
    2. options參數
      1. WNOHANG:若由pid指定的子程序沒有退出則立即傳回,則waitpid不阻塞,此時傳回值為0
      2. WUNTRACED:若某實作支援作業控制,則由pid指定的任一子程序狀态已暫停,且其狀态自暫停以來還未報告過,則傳回其狀态
    3. 檢查 wait 和 waitpid 函數傳回終止狀态的宏(前面判斷,後面獲得狀态碼)
      1. WIFEXITED/WEXITSTATUS(status):若為正常終止子程序的傳回的狀态,則為真
      2. WIFSIGNALED/WTERMSIG(status):若為異常終止子程序的傳回的狀态,則為真(接到一個不能捕捉的信号)
      3. WIFSTOPED/WSTOPSIG(status):若為目前暫停子程序的傳回的狀态,則為真(如果目前程序在終止前暫停過,則獲得暫停的狀态碼)

2. wait函數

  1. 原型:

    pid_t wait(int *status)

  2. 傳回:成功傳回子程序ID,出錯傳回-1
  3. 作用:等待子程序退出并回收,防止僵屍程序産生

3. waitpid函數

  1. 原型:

    pid_t waitpid(pid_t pid, int *status, int options)

  2. 傳回:成功傳回子程序ID,出錯傳回-1
  3. 功能:wait函數的非阻塞版本
  4. pid參數:
    1. pid == -1:等待任一子程序,與功能 wait 相等
    2. pid > 0:等待其程序ID與 pid 相等的子程序
    3. pid == 0:等待其組ID等于調用程序的組ID的任一子程序
    4. 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 ;
    }
           
  • 運作測試
    1. 運作程式
      wait函數和waitpid函數
    2. 發送信号給程式
      wait函數和waitpid函數
    3. 測試結果
      wait函數和waitpid函數