[Linux system programming] 23. Orphan process, zombie process, wait, waitpid

Table of contents

orphan process

test code 1

Test Results

zombie process

Test code 2

Test Results

wait

Parameter *wstatus

return value

Test code 3

Test Results

Test code 4

Test Results

Test code 5

Test Results

waitpid

parameter pid

Parameter *wstatus

parameter options

return value

Test code 6

Test Results

Test code 7

Test Results

Test code 8

Test Results

Test code 9

Test Results

Test code 10

Test Results

orphan process

        If the parent process ends before the child process, the child process becomes an orphan process, and the parent process of the child process becomes the init process, which is called the init process adopts the orphan process.

test code 1

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
    printf("程序开始运行!\n");
    printf("当前进程的ID是%d。\n", getpid());
    pid_t jin_cheng = fork();
    if (jin_cheng < 0)
    {
        perror("创建进程错误!");
        exit(1);
    }
    else if (jin_cheng == 0)
    {
        while(1){
            printf("这是子进程,当前进程的ID是%d,父进程ID是%d。\n", getpid(),getppid());
            sleep(1);
        }
    }
    else if (jin_cheng > 0)
    {
        sleep(3);
        printf("这是父进程,当前进程的ID是%d,子进程ID是%d。\n", getpid(),jin_cheng);
        printf("父程序结束!\n");
        printf("孤儿进程产生!\n");
    }
    return 0;
}

Test Results

View the corresponding parent process of the process.

ps ajx

 

 After the parent process dies, it is adopted by the 1319 process.

 

zombie process

        The process terminates, the parent process has not been recycled, and the residual resources (PCB) of the child process are stored in the kernel and become a zombie process. Zombie processes cannot be removed using the kill command. Because the kill command is only used to terminate the process, and the zombie process has been terminated.

Test code 2

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
    printf("程序开始运行!\n");
    printf("当前进程的ID是%d。\n", getpid());
    pid_t jin_cheng = fork();
    if (jin_cheng < 0)
    {
        perror("创建进程错误!");
        exit(1);
    }
    else if (jin_cheng == 0)
    {
        sleep(3);
        printf("这是子进程,当前进程的ID是%d,父进程ID是%d。\n", getpid(), getppid());
        printf("子进程结束!\n");
        printf("僵尸进程产生!\n");
    }
    else if (jin_cheng > 0)
    {
        while (1)
        {
            printf("这是父进程,当前进程的ID是%d,子进程ID是%d。\n", getpid(), jin_cheng);
            sleep(1);
        }
    }
    return 0;
}

Test Results

 6138 The process has died and has become a zombie process, waiting for the parent process to recycle.

 To get rid of a zombie process, you can kill the parent process.

kill -9 6137

 

wait

        When a process terminates, it closes all file descriptors and releases the memory allocated in user space, but its PCB is still reserved, and the kernel saves some information in it: if it terminates normally, it saves the exit status, and if it terminates abnormally It stores which signal caused the process to terminate. The parent process of this process can call wait or waitpid to obtain this information, and then completely clear this process.

        The parent process calls the wait function to recycle the child process termination information. This function has three functions:

  1. Blocking and waiting for the child process to exit is equivalent to waiting for the child process to die.

  2. Reclaim the remaining resources of the child process.

  3. Get the end status of the child process (exit reason).

        When a process terminates, the operating system's implicit recycling mechanism:

  1. Close all file descriptors.

  2. Frees memory allocated by user space.

        The kernel's PCB still exists, where the exit status of the process is saved. You can use the wait function to pass out the parameter status to save the exit status of the process. Use the macro function to further determine the specific reason for the process termination.

 Process ended normally

WIFEXITED(status)!=0

 Get the exit status of the process (the parameter of exit), which can be used when the process ends normally.

WEXITSTATUS(status)

 Process terminated abnormally

WIFSIGNALED(status)!=0

 Get the number of the signal that causes the process to terminate, which can be used when the process terminates abnormally.

WTERMSIG(status)

 process is suspended

WIFSTOPPED(status)!=0

 Get the number of the signal that caused the process to suspend, which can be used when the process is suspended.

WSTOPSIG(status)

 The process has continued running after being suspended

WIFCONTINUED(status)!=0

 The parent process is awesome, and does not care about the cause of the death of the child process, and the parameter is passed NULL.

ZiJinCheng_ID = wait(NULL);
man 2 wait

Parameter *wstatus

The outgoing parameter, the status of the recycling process.

return value

Success: The process ID of the child that was cleaned up.

Failed: -1, no child processes.

Test code 3

Use wait to recycle the process.

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>

int main(int argc, char *argv[])
{
    int i, wstatus;
    pid_t ZiJinCheng_ID; //子进程ID
    printf("程序开始运行!\n");
    printf("当前进程的ID是%d。\n", getpid());
    pid_t jin_cheng = fork();
    if (jin_cheng < 0)
    {
        perror("创建进程错误!");
        exit(1);
    }
    else if (jin_cheng == 0)
    {
        for (i = 0; i < 3; i++)
        {
            printf("这是子进程,当前进程的ID是%d,父进程ID是%d,延时%d秒。\n", getpid(), getppid(), i + 1);
            sleep(1);
        }
        printf("子进程结束!\n");
        printf("僵尸进程产生!\n");
    }
    else if (jin_cheng > 0)
    {
        printf("这是父进程,当前进程的ID是%d,子进程ID是%d,父进程开始等待收尸!\n", getpid(), jin_cheng);
        ZiJinCheng_ID = wait(&wstatus);
        printf("这是父进程,当前进程的ID是%d,子进程ID是%d,父进程收尸完成,僵尸进程ID是%d。\n", getpid(), jin_cheng, ZiJinCheng_ID);
        printf("父程序结束!\n");
    }
    return 0;
}

Test Results

Test code 4

View the normal termination of the child process.

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>

int main(int argc, char *argv[])
{
    int i, wstatus;
    pid_t ZiJinCheng_ID; //子进程ID
    printf("程序开始运行!\n");
    printf("当前进程的ID是%d。\n", getpid());
    pid_t jin_cheng = fork();
    if (jin_cheng < 0)
    {
        perror("创建进程错误!");
        exit(1);
    }
    else if (jin_cheng == 0)
    {
        for (i = 0; i < 3; i++)
        {
            printf("这是子进程,当前进程的ID是%d,父进程ID是%d,延时%d秒。\n", getpid(), getppid(), i + 1);
            sleep(1);
        }
        printf("子进程结束!\n");
        printf("僵尸进程产生!\n");
        return 100;
    }
    else if (jin_cheng > 0)
    {
        printf("这是父进程,当前进程的ID是%d,子进程ID是%d,父进程开始等待收尸!\n", getpid(), jin_cheng);
        ZiJinCheng_ID = wait(&wstatus); //子进程未结束,父进程阻塞在这个函数上
        printf("这是父进程,当前进程的ID是%d,子进程ID是%d,父进程收尸完成,僵尸进程ID是%d。\n", getpid(), jin_cheng, ZiJinCheng_ID);
        if (WIFEXITED(wstatus)) //判断子进程是否正常结束
        {
            printf("子进程正常死亡,死亡原因:%d。\n", WEXITSTATUS(wstatus));
        }
        if (WIFSIGNALED(wstatus)) //判断子进程是否异常结束
        {
            printf("子进程被杀,终止信号是%d。\n", WTERMSIG(wstatus));
        }
        printf("父程序结束!\n");
    }
    return 0;
}

Test Results

Test code 5

View the abnormal termination of the child process.

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>

int main(int argc, char *argv[])
{
    int i, wstatus;
    pid_t ZiJinCheng_ID; //子进程ID
    printf("程序开始运行!\n");
    printf("当前进程的ID是%d。\n", getpid());
    pid_t jin_cheng = fork();
    if (jin_cheng < 0)
    {
        perror("创建进程错误!");
        exit(1);
    }
    else if (jin_cheng == 0)
    {
        while(1)
        {
            printf("这是子进程,当前进程的ID是%d,父进程ID是%d,我是长生不老的。\n", getpid(), getppid());
            sleep(1);
        }
    }
    else if (jin_cheng > 0)
    {
        printf("这是父进程,当前进程的ID是%d,子进程ID是%d,父进程开始等待收尸!\n", getpid(), jin_cheng);
        ZiJinCheng_ID = wait(&wstatus); //子进程未结束,父进程阻塞在这个函数上
        printf("这是父进程,当前进程的ID是%d,子进程ID是%d,父进程收尸完成,僵尸进程ID是%d。\n", getpid(), jin_cheng, ZiJinCheng_ID);
        if (WIFEXITED(wstatus)) //判断子进程是否正常结束
        {
            printf("子进程正常死亡,死亡原因:%d。\n", WEXITSTATUS(wstatus));
        }
        if (WIFSIGNALED(wstatus)) //判断子进程是否异常结束
        {
            printf("子进程被杀,终止信号是%d,还说是长生不老,直接把你给杀了。\n", WTERMSIG(wstatus));
        }
        printf("父程序结束!\n");
    }
    return 0;
}

Test Results

waitpid

Designate a process for recycling.

man 2 waitpid

 

parameter pid

Greater than 0: Specifies the ID of the recycled child process.

0: Recycle all child processes in the same group as the current call to waitpid.

-1: Recycle any child process.

Less than -1: Recycle any child process in the specified process group.

Parameter *wstatus

The outgoing parameter, the status of the recycling process.

parameter options

WNOHANG: Specifies that the recycling method is non-blocking.

0: Block recycling, the function is equal to the wait function.

return value

Greater than 0: the PID of the child process is successfully recycled.

0: When the function is called, the parameter options specifies WNOHANG, and the child process does not end.

-1: Failed.

Test code 6

Recycles the specified one process in a non-blocking manner. The parent process does not delay, the child process does not end, and returns 0.

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>

int main(int argc, char *argv[])
{
    int i;
    pid_t temp_ZiJinCheng_ID;  //临时子进程ID
    pid_t JinCheng_ID;         //子进程ID
    pid_t HuiShou_JinCheng_ID; //回收进程ID
    printf("程序开始运行!\n");
    printf("当前进程的ID是%d。\n", getpid());
    printf("开始创建进程!\n");
    for (i = 0; i < 5; i++)
    {
        temp_ZiJinCheng_ID = fork();
        if (temp_ZiJinCheng_ID == 0) //子进程,不参与创建进程
        {
            break;
        }
        if (i == 2)
        {
            JinCheng_ID = temp_ZiJinCheng_ID;
        }
    }
    if (i == 5)
    {
        HuiShou_JinCheng_ID=waitpid(JinCheng_ID,NULL,WNOHANG);//以非阻塞的方式回收一个进程ID,JinChen_ID
        if(HuiShou_JinCheng_ID<0){
            perror("回收进程错误");
            exit(1);
        }
        printf("这是父进程,当前进程的ID是%d,回收的子进程是%d。\n", getpid(),HuiShou_JinCheng_ID);
    }
    else
    {
        sleep(i); //延时i秒,按顺序输出
        printf("这是第%d个子进程,当前进程的ID是%d。\n", i + 1, getpid());
    }
    return 0;
}

Test Results

Test code 7

Recycles the specified one process in a non-blocking manner. The parent process delays, the child process ends, and returns the recovered process ID.

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>

int main(int argc, char *argv[])
{
    int i;
    pid_t temp_ZiJinCheng_ID;  //临时子进程ID
    pid_t JinCheng_ID;         //子进程ID
    pid_t HuiShou_JinCheng_ID; //回收进程ID
    printf("程序开始运行!\n");
    printf("当前进程的ID是%d。\n", getpid());
    printf("开始创建进程!\n");
    for (i = 0; i < 5; i++)
    {
        temp_ZiJinCheng_ID = fork();
        if (temp_ZiJinCheng_ID == 0) //子进程,不参与创建进程
        {
            break;
        }
        if (i == 2)
        {
            JinCheng_ID = temp_ZiJinCheng_ID;
        }
    }
    if (i == 5)
    {
        sleep(5); //延时,最后输出父进程
        HuiShou_JinCheng_ID = waitpid(JinCheng_ID, NULL, WNOHANG); //以非阻塞的方式回收一个进程ID,JinChen_ID
        if (HuiShou_JinCheng_ID < 0)
        {
            perror("回收进程错误");
            exit(1);
        }
        printf("这是父进程,当前进程的ID是%d,回收的子进程是%d。\n", getpid(), HuiShou_JinCheng_ID);
    }
    else
    {
        sleep(i); //延时i秒,按顺序输出
        printf("这是第%d个子进程,当前进程的ID是%d。\n", i + 1, getpid());
    }
    return 0;
}

Test Results

Test code 8

Recycle an arbitrary child process.

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>

int main(int argc, char *argv[])
{
    int i;
    pid_t temp_ZiJinCheng_ID;  //临时子进程ID
    pid_t HuiShou_JinCheng_ID; //回收进程ID
    printf("程序开始运行!\n");
    printf("当前进程的ID是%d。\n", getpid());
    printf("开始创建进程!\n");
    for (i = 0; i < 5; i++)
    {
        temp_ZiJinCheng_ID = fork();
        if (temp_ZiJinCheng_ID == 0) //子进程,不参与创建进程
        {
            break;
        }
    }
    if (i == 5)
    {
        sleep(6);	//延时,确保所有子进程都已经结束,最后输出父进程
        HuiShou_JinCheng_ID = waitpid(-1, NULL, WNOHANG); //以非阻塞的方式回收任意一个子进程ID
        if (HuiShou_JinCheng_ID < 0)
        {
            perror("回收进程错误");
            exit(1);
        }
        printf("这是父进程,当前进程的ID是%d,回收的子进程是%d。\n", getpid(), HuiShou_JinCheng_ID);
    }
    else
    {
        sleep(i); //延时i秒,按顺序输出
        printf("这是第%d个子进程,当前进程的ID是%d。\n", i + 1, getpid());
    }
    return 0;
}

Test Results

        The online tutorial says to recycle any sub-process, but judging from the results, the first sub-process that ends is recycled every time. It does not rule out that the newer version of the Ubuntu system has optimized the algorithm of recycling processes, and realizes that the first end is the first to be recycled. Condition.

 

Test code 9

Recycle all dead child processes in a blocking manner.

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>

int main(int argc, char *argv[])
{
    int i;
    pid_t temp_ZiJinCheng_ID;  //临时子进程ID
    pid_t HuiShou_JinCheng_ID; //回收进程ID
    printf("程序开始运行!\n");
    printf("当前进程的ID是%d。\n", getpid());
    printf("开始创建进程!\n");
    for (i = 0; i < 5; i++)
    {
        temp_ZiJinCheng_ID = fork();
        if (temp_ZiJinCheng_ID == 0) //子进程,不参与创建进程
        {
            break;
        }
    }
    if (i == 5)
    {
        while ((HuiShou_JinCheng_ID = waitpid(-1, NULL, 0)) != -1) //以阻塞的方式回收任意一个子进程ID
        {
            printf("这是父进程,当前进程的ID是%d,回收的子进程是%d。\n", getpid(), HuiShou_JinCheng_ID);
        }
        if (HuiShou_JinCheng_ID < 0)
        {
            perror("这是父进程,回收子进程完成,父进程结束!\n");
        }
    }
    else
    {
        sleep(i); //延时i秒,按顺序输出
        printf("这是第%d个子进程,当前进程的ID是%d。\n", i + 1, getpid());
    }
    return 0;
}

Test Results

Test code 10

Recycle all dead child processes in a non-blocking manner.

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>

int main(int argc, char *argv[])
{
    int i;
    pid_t temp_ZiJinCheng_ID;  //临时子进程ID
    pid_t HuiShou_JinCheng_ID; //回收进程ID
    printf("程序开始运行!\n");
    printf("当前进程的ID是%d。\n", getpid());
    printf("开始创建进程!\n");
    for (i = 0; i < 5; i++)
    {
        temp_ZiJinCheng_ID = fork();
        if (temp_ZiJinCheng_ID == 0) //子进程,不参与创建进程
        {
            break;
        }
    }
    if (i == 5)
    {
        sleep(6);                                                  //延时,确保所有的子进程都死亡
        while ((HuiShou_JinCheng_ID = waitpid(-1, NULL, WNOHANG)) != -1) //以非阻塞的方式回收任意一个子进程ID
        {
            printf("这是父进程,当前进程的ID是%d,回收的子进程是%d。\n", getpid(), HuiShou_JinCheng_ID);
        }
        if (HuiShou_JinCheng_ID < 0)
        {
            perror("这是父进程,回收子进程完成,父进程结束!\n");
        }
    }
    else
    {
        sleep(i); //延时i秒,按顺序输出
        printf("这是第%d个子进程,当前进程的ID是%d,该进程结束。\n", i + 1, getpid());
    }
    return 0;
}

Test Results

 

Guess you like

Origin blog.csdn.net/CETET/article/details/132267131