狂自私

导航

在Linux中简单实现回收子进程

学习到wait函数了,这个函数的作用是用来回收进程。一般来说,正常退出的进程是不需要我们来专门回收的。但是进程有这两种:孤儿进程和僵尸进程。

孤儿进程:

通俗点说就是父进程先于子进程死亡。此时子进程就成为孤儿进程。这时候子进程的父进程就是init进程了。这个过程(父进程死亡后子进程的父进程变为init)称为init进程领养孤儿进程。

僵尸进程

进程终止,但是父进程并未进行回收操作。子进程的残留资源(PCB)存在于内核中,成为僵尸进程。就是儿子死了,但是父亲不收尸。

这里要注重理解的是:僵尸进程实际上是结束的进程。所以,我们能用kill命令结束它么?不能!结束一个已经结束的进程。怎么能行呢?

请看下列代码:

#include <cstdio>

#include <stdlib.h>

#include <unistd.h>

int p = 111;

//pid_t fork(void);//在父进程中返回子进程的id,在子进程返回0(没有子进程了嘛,因为)。

int main(int argc, char*argv[])//有用户指定创建多少个子进程

{

    printf("hello from Create_N_subprocesses!\n");

    if (argc < 2)

    {

        printf("Too few parameters\n");

        exit(1);

    }

    int i, n = atoi(argv[1]);

    for (i = 0; i < n; i++)

    {

        if (0 == fork())//父进程中返回的不是0,继续执行for循环;在子进程中返回0,for循环结束。

        {

            break;

        }

    }

    //基本上每个父子进程是同时进行。所以睡眠时间依次递增。

    sleep(i);

    if (i < n)//父进程不能算在里面

    {

        p++;//这里改变p的值

        printf("I am the %d process.\n p = %d\n", i + 1, p);//这里的每个p都一样,哪怕每次p都会自增

    }

    else

    {

        printf("my father process \n p = %d\n", p);//但是这里还是会输出111

    }

    /*

    p用来验证父子之间可以用静态变量传递消息么?

    答案是不可以,因为date段是独立的。

    父子之间遵循读时共享,写是独立的原则。

    */

    return 0;

}

这是一段用于创建N个子进程的程序代码。并且验证父子进程之间能够进行资源共享的资源共享方式是:读时共享写时独立。这些都不是重点。重点是,这个程序执行后会产生N个僵尸进程。为什么?因为我们没有进行回收。怎么回收?用wait()函数。

wait函数:该函数有三个功能:

1.阻塞等待子进程退出 (如果该子进程没有死亡,父进程阻塞,不做其他的事。)

2.回收子进程残留资源

3.获取子进程结束状态(退出原因)。

原型:pid_t wait(int *status);

返回值:成功:清理掉的子进程ID;失败:-1 (没有子进程)

需要注意的是:回收进程的工作是由当前进程的父进程来做。调用一次wait函数只会回收一个进程,若是多个进程死亡,wait函数只会回收最先死亡的那个进程。

上代码:

#include <stdlib.h>

#include <stdio.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/wait.h>

 

int main()

{

    int status;

    int i = 0;

    pid_t pid_1, pid_2;

 

    for (; i != 1; i++)

    {

        pid_1 = fork();

        if (!pid_1)

        {

            break;

        }

    }

    if (i < 1)

    {

        sleep(5);

        printf("I am the %d child.my ID is %d .\n", i + 1, getpid());

    }

    else

    {

        pid_2 = wait(&status);

        if (-1 == pid_2)

        {

            perror("wait precess ");

            exit(1);

        }

        printf("Recovery of the %d process is successful.It is ID %d .\n", i, pid_2);

        if (WIFEXITED(status))

        {

            printf("Normal exit of process, Exit status : %d .\n", WEXITSTATUS(status));

        }

        else if (WIFSIGNALED(status))

        {

            printf("The program exits with abnormal signal, signal value : %d.\n", WTERMSIG(status));

        }

 

        printf("I am is father.\n");

    }

 

    //printf("hello from Recycle_child_process!\n");

    return 0;

}

我fork了一个子进程,并让它休眠5s。注意我的wait函数是在父进程分支中调用的,这里涉及到几个宏函数:

WIFEXITED(status) 为非0     进程正常结束

WEXITSTATUS(status) 如上宏为真,使用此宏 获取进程退出状态 (exit的参数)

WIFSIGNALED(status) 为非0 进程异常终止

WTERMSIG(status) 如上宏为真,使用此宏 取得使进程终止的那个信号的编号。

这样,程序会输出:

I am the 1 child.my ID is 6024 .
Recovery of the 1 process is successful.It is ID 6024 .
Normal exit of process,Exit status:0 .
I am is father.

ID应该是不会一样的。

程序显示该子进程是正常退出的,返回值为0;我们可以改动这个返回值:用return 语句

if (i < 1)

{

    sleep(5);

    printf("I am the %d child.my ID is %d .\n", i + 1, getpid());

    return 1314520;

}

那么程序的输出就应该是:

I am the 1 child.my ID is 6024 .
Recovery of the 1 process is successful.It is ID 6024 .
Normal exit of process,Exit status:1314520 .
I am is father.

那我们怎么让子进程异常退出?毕竟平常也很少遇到。我们可以人为的营造环境,段错误知道吧?浮点异常知道吧?不知道可以百度或谷歌。

我们来编写一个程序:

#include <stdio.h>

int main(void)

{

    int i = 5 / 0;//浮点异常

    char *p = "love dandan";

    p[2] = 69;

    return 0;

}

 

编译并命名为a.out。然后我们修改程序为:

if (i < 1)

{

    execl(" / home / lovedan / projects / Recycle_child_process / bin / x64 / Debug / a.out", "a.out", NULL);//第一个参数一定是绝对路径。相信你知道execl函数

                /*sleep(5);

                printf("I am the %d child.my ID is %d .\n", i + 1, getpid());*/

}

这时候,程序的输出。。。。输出结果我丢失了,也不想在去重新弄了。反正吧,他会输出子进程被成功回收,但是子进程是异常退出。提示浮点异常,value值是8(即:SIGFPE)。将in i=5/0;注释掉之后在编译它,重新运行另外一个程序输出结果又会不一样。会提示我们子进程因为段错误而退出。

大概就这些吧,后面还有一个waitpid函数。后面在来介绍吧。

   

来更新一下:循环回收多个子进程:

上面的示例是指创建回收一个子进程,若是我们创建多个,该如何回收呢?用循环!

for (; i != 10; i++)

{

    pid_1 = fork();

    if (!pid_1)

    {

        break;

    }

}

if (i < 10)

{

    sleep(i);

    printf("I am the %d child.my ID is %d .\n", i + 1, getpid());

}

else

{

    sleep(i);

    while (pid_2 = wait(&status) != -1)//循环回收进程

    {

        printf("Recovery of the %d process is successful.It is ID %d .\n", i, pid_2);

 

        if (WIFEXITED(status))

        {

            printf("Normal exit of process, Exit status : %d .\n", WEXITSTATUS(status));

        }

        else if (WIFSIGNALED(status))

        {

            printf("The program exits with abnormal signal, signal value : %d.\n", WTERMSIG(status));

        }

 

 

        printf("I am is father.\n");

    }

 

    if (-1 == pid_2)

    {

        perror("wait precess ");

        exit(1);

    }

}

我就只是贴了我修改的代码。其实变动很少,就是加个循环控制而已,这个程序的输出是:

I am the 1 child.my ID is 1225 .
I am the 2 child.my ID is 1226 .
I am the 3 child.my ID is 1227 .
I am the 4 child.my ID is 1228 .
I am the 5 child.my ID is 1229 .
I am the 6 child.my ID is 1230 .
I am the 7 child.my ID is 1231 .
I am the 8 child.my ID is 1232 .
I am the 9 child.my ID is 1233 .
I am the 10 child.my ID is 1234 .
Recovery of the 10 process is successful.It is ID 1 .
Normal exit of process,Exit status:0 .
I am is father.
Recovery of the 10 process is successful.It is ID 1 .
Normal exit of process,Exit status:0 .
I am is father.
Recovery of the 10 process is successful.It is ID 1 .
Normal exit of process,Exit status:0 .
I am is father.
Recovery of the 10 process is successful.It is ID 1 .
Normal exit of process,Exit status:0 .
I am is father.
Recovery of the 10 process is successful.It is ID 1 .
Normal exit of process,Exit status:0 .
I am is father.
Recovery of the 10 process is successful.It is ID 1 .
Normal exit of process,Exit status:0 .
I am is father.
Recovery of the 10 process is successful.It is ID 1 .
Normal exit of process,Exit status:0 .
I am is father.
Recovery of the 10 process is successful.It is ID 1 .
Normal exit of process,Exit status:0 .
I am is father.
Recovery of the 10 process is successful.It is ID 1 .
Normal exit of process,Exit status:0 .
I am is father.
Recovery of the 10 process is successful.It is ID 1 .
Normal exit of process,Exit status:0 .
I am is father.

有没有发现回收的ID全为1?因为子进程先于父进程结束啊,是正常的结束,返回值为0;如果想要测试异常结束,请自行营造环境。

posted on 2018-04-05 20:40  狂自私  阅读(502)  评论(0编辑  收藏  举报