Linux 进程(第二阶段)

6.vfork创建进程

下图是fork与vfork的区别:
在这里插入图片描述
下面我们来对比一下fork和vfork的区别:首先看fork的代码(demo8.c)

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
        pid_t pid;

        printf("father pid = %d\n",getpid());

        pid = fork();
        
        if(pid > 0)
        {
                while(1){
                        printf("this is father print,pid = %d\n",getpid());
                        sleep(1);
                }
        }
        else if(pid == 0){
                while(1){
                        printf("this is child print,child pid = %d\n",getpid());
                        sleep(1);
                }
        }

        return 0;
}


下图是运行的结果图:可以看出父子进程执行争夺cpu不一定是一人一次,有可能父先也有可能是子先(取决于进程的调度)。
在这里插入图片描述
当改成vfork的时候,都是子进程先运行,直到子进程退出父进程才运行。代码是demo11.c

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
        pid_t pid;
        int cnt = 0;

        printf("father pid = %d\n",getpid());

        pid = vfork();

        if(pid > 0)
        {
                while(1){
                        printf("this is father print,pid = %d\n",getpid());
                        sleep(1);
                        printf("cnt=%d\n",cnt);//这里打印出来的数据是经过子进程修改的,即子进程是用父进程的空间。
                }
        }
        else if(pid == 0){
                while(1){
                        printf("this is child print,child pid = %d\n",getpid());
                        sleep(1);
                        cnt++;
                        if(cnt == 3){
                                exit(0);//这里之前用break退出,破坏了cnt的值,所以子进程退出要用好的方式退出。
                        }
                }
        }

        return 0;
}

下图是运行结果图(子进程运行结束退出后父进程才开始运行)
在这里插入图片描述

7.进程退出

退出情况有两种:1、正常退出;2、异常退出
正常退出情况方式如图:
在这里插入图片描述
异常退出情况的方式如图:
在这里插入图片描述
正常退出的函数如下:(建议用exit函数退出,因为它是对另外两个函数的封装,会对缓冲区的内容做一些处理再退出,另外两个直接退出)
在这里插入图片描述

8.父进程等待子进程退出(一)

子进程退出的状态码(exit(3)),那么父进程wait(状态码)不会等于3,需要经过下图的宏解析一下才可以等于3。
****补充:WIFEXITED(status)是可以判断子进程是否正常退出,用法比如if(WIFEXITED(status)){ 用WEXITSTATUS(status)//解析退出码 }else{ }
在这里插入图片描述

子进程退出状态不被收集就是僵尸进程,代码为(demo12.c)写的比较全面(啰嗦),这里是用vfork创建的子进程,用fork也是一样(demo13.c 这里没有写,运行结果是cnt没有变成3,而是0,因为fork的子进程不与父进程共享空间)的,子进程也会变成僵尸进程。

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
        pid_t pid;
        int cnt = 0;

        printf("father pid = %d\n",getpid());

        pid = vfork();//pid = fork();

        if(pid > 0)
        {
                while(1){
                        printf("this is father print,pid = %d\n",getpid());//这一段子进程的退出码都没有被收集
                        sleep(1);
                        printf("cnt=%d\n",cnt);
                }
        }
        else if(pid == 0){
                while(1){
                        printf("this is child print,child pid = %d\n",getpid());
                        sleep(1);
                        cnt++;
                        if(cnt == 3){
                                exit(0);
                        }
                }
        }

        return 0;
}

僵尸进程的图如下:
在这里插入图片描述
使得父进程等待子进程退出有以下几个api(使用了api就可以使得子进程不变成僵尸进程),本节主要使用wait函数就可以使得子进程变为非僵尸进程,但是,其状态值的存放有两种情况(参数是NULL或这非空),下图是wait函数的原函数及其他api部分讲解
在这里插入图片描述
情况1(wait(NULL))
父进程等待子进程退出但是不收集子进程的退出状态代码(也就是多了wait(NULL)demo14.c)
这里只是父进程部分代码,因为其他的部分一样的和上面代码

 if(pid > 0)
        {
                wait(NULL);//就是调用wait函数(子进程先运行,父进程在等待),但是并不关心子进程的退出码,但是就是因为有这个wait,子进程不再是僵尸进程。
                while(1){
                        printf("this is father print,pid = %d\n",getpid());
                        sleep(1);
                        printf("cnt=%d\n",cnt);
                }
        }

代码运行结果为:
在这里插入图片描述
情况2(wait(参数))
父进程创建子进程干活,子进程退出,父进程并把子进程的退出码获取,并经过宏解析的代码(demo15.c)

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

int main()
{
        pid_t pid;
        int cnt = 0;
        int status =10;

        printf("father pid = %d\n",getpid());

        pid = fork();

        if(pid > 0)
        {
                wait(&status);//父进程获取退出码,切记取的是地址
                printf("child quit,child status = %d\n",WEXITSTATUS(status));//用宏解析退出码打印子进程退出码
                while(1){
                        printf("this is father print,pid = %d\n",getpid());
                        sleep(1);
                        printf("cnt=%d\n",cnt);
                }
        }
        else if(pid == 0){
                while(1){
                        printf("this is child print,child pid = %d\n",getpid());
                        sleep(1);
                        cnt++;
                        if(cnt == 5){
                                exit(3);//子进程退出
                        }
                }
        }

        return 0;
}

运行结果如下图:(退出码为3,正确的)
在这里插入图片描述

9.父进程等待子进程退出(二)

父进程等待子进程有以下几个API上面使用的是wait等待子进程的退出,这里就是wait与waitpid的区别图如下:

在这里插入图片描述
下图是对waitpid参数的解读(这个api实战中用的并不多,目前没有好的场景运用,先看看怎么调用吧,(在demo16.c)):
在这里插入图片描述
废话不多说,直接撸代码(demo16.c)这里就是修改了父进程的代码,其他和上面的代码一样。

if(pid > 0)
        {
                //wait(&status);
                waitpid(pid,&status,WNOHANG);//就是把wait替代成这个api,子进程和父进程都在运行,父进程没有被阻塞。
                printf("child quit,child status = %d\n",WEXITSTATUS(status));
                while(1){
                        printf("this is father print,pid = %d\n",getpid());
                        sleep(1);
                        printf("cnt=%d\n",cnt);
                }
        }

运行结果如图:(经过ps指令查询,子进程不一定是僵尸进程,我这边不是僵尸进程,老陈的是僵尸进程)
在这里插入图片描述
孤儿进程
下图是孤儿进程的概念:
在这里插入图片描述
编程验证:
新API :在子进程中获取父进程的pid号函数是(getppid())

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

int main()
{
        pid_t pid;
        int cnt = 0;

        pid = fork();

        if(pid > 0)
        {
                printf("this is father print,father pid = %d\n",getpid());//父进程提早结束
        }
        else if(pid == 0){
                while(1){
                        printf("this is child print,child pid = %d,my father pid=%d\n",getpid(),getppid());
                        sleep(1);
                        cnt++;
                        if(cnt == 5){
                                exit(3);
                        }
                }
        }

        return 0;
}

运行结果如下图:(孤儿进程被图形界面收了,所以pid是1693,所以需要进入字符界面运行,才会被init的子进程接管(https://blog.csdn.net/u012206617/article/details/93088996介绍init知识),如何进入字符界面运行?)
在这里插入图片描述
补充一个linux系统编程的书写的比较好的demo
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值