Linux进程创建之fork与进程状态

时间:2021-09-22 17:33:38

写在前面:小生纯业余选手,开此博仅仅是为了积累,纯当笔记来用。如有看官光临小生博客,请不要相信我的代码就是正确的。如果您发现了错误也恳请耽误您一点时间,请您在下面指出来,不胜感激!

如果发现一些笔记的说法完全是错误的请建议我删除!


通过fork可以创建新的进程,通过fork创建的新进程称作子进程,原进程称作父进程。父进程与子进程是两个独立的进程,他们不会因“父子”关系来放弃使用CPU或内存资源。他们各自在proc下创建各自的文件。


问题:

如果进程A创建了进程a

1.进程A在执行过程中退出了而进程a还在继续执行,进程a会怎样?

回答:进程a将成为孤儿进程统一挂在Linux的根进程下。

2.进程A在执行的过程中进程a退出了,进程a会怎样?

回答:进程a将成为僵死进程,占用了进程任务管理树的一个节点,如果僵死进程过多会产生问题,所以要回收僵死进程。

3.问题如何回收僵死进程,如何知道a进程处于僵死状态?


可以通过pstree命令来观察Linux进程树,ps命令来观察进程

僵死进程会在进程树中占用一个节点,通过ps命令可以看到僵死进程的STAT是Z……<defunct>

下图是Linux进程树

Linux进程创建之fork与进程状态

注意上图左侧黑色大括号的部分


运行如下代码观察进程树中大括号部分的内容

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

int main()
{
    if(fork() == 0)
    {
        printf("child\n");
        sleep(200);
        printf("child quit\n");
        while(1);
    }
    else
    {
        sleep(20);
        printf("parent quit!\n");
        while(1);
    }
    return 0;
} 
进程树中的黑色大括号部分如下

Linux进程创建之fork与进程状态


如下代码产生一个孤儿进程,通过pstree命令可以看到孤儿进程将被挂在根进程(init进程)下。

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

int main()
{
    if(fork() == 0)
    {
        sleep(40);
        printf("child quit\n");
    }
    else
    {
        sleep(20);
        printf("parent quit!\n");
    }
    return 0;
} 


如下代码产生一个僵死进程,通过ps命令可以看到僵死进程的状态,通过pstree命令可以看到僵死进程依然占用了进程树中的一个节点。

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

int main()
{
    if(fork() == 0)
    {
        sleep(20);
        printf("child quit\n");
    }
    else
    {
        sleep(40);
        printf("parent quit!\n");
    }
    return 0;
} 


通过wait来回收僵死进程,通过ps命令查看不注释wait,与注释wait的区别

<span style="font-size:18px;">#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<signal.h>

int main()
{
    if(fork() == 0)
    {
        sleep(20);
        printf("child quit\n");
    }
    else
    {
        int status;
        wait(&status);
        printf("colecting defunct\n",WEXITSTATUS(status));
        sleep(40);
    }
    return 0;
}</span>

对于上一个例子只需要等待子进程结束就能通过wait回收,但是子进程会在什么时候结束呢?这就需要通过Linux信号的机制来实现,下面代码简单说明信号的应用。

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

void deal(int s)
{
    int status;
    wait(&status);
    printf("collecting............\n");
    sleep(10);
    printf("collecting over:%d\n",WEXITSTATUS(status));
}

int main()
{
    if(fork() == 0)
    {
        sleep(20);
        printf("child quit\n");
    }
    else
    {
        signal(SIGCHLD,deal);
        while(1)
        {
            sleep(1);
            printf("parent\n");
        }
    }
    return 0;
}


Linux进程创建之fork与进程状态
上面代码段中signal函数在哪个进程中被调用,使用权就属于哪一个进程。signal函数要在调用结束之后才返回到调用signal的进程中继续进程的执行(通过deal函数中的sleep函数可以清楚地看到这一点)!