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()) < 0){
            perror("fork error");
            exit(1);
        }
        else if(pid == 0){
            printf("pid: %d, ppid: %d\n", getpid(), getppid());
            exit(3); //子進程終止運行
        }

        //父進程阻塞,等待子進程結束並回收
        wait(&status);
        out_status(status);

        printf("--------------------------\n");

        if((pid = fork()) < 0){
            perror("fork error");
            exit(1);
        }
        else if(pid == 0){
            printf("pid: %d, ppid: %d\n", getpid(), getppid());

            int i = 3, j = 0;
            int k = i / j;  //異常測試
            printf("k: %d\n", k);
        }

        wait(&status);
        out_status(status);
        printf("--------------------------\n");


        if((pid = fork()) < 0){
            perror("fork error");
            exit(1);
        }
        else if(pid == 0){
            printf("pid: %d, ppid: %d\n", getpid(), getppid());
            pause();  //暫停測試
        }

        do{
            //暫停測試需要用waitpid來捕獲暫停的信號,並返回
            pid = waitpid(pid, &status, WNOHANG | WUNTRACED);

            if(pid == 0){
                sleep(1);
            }
        }while(pid == 0);
        out_status(status);

        return 0;
    }
  • 運行測試

    1. 運行程序

      測試

    2. 發送信號給程序

      測試

    3. 測試結果

      測試

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章