linux中进程相关概念(二)

父进程等待子进程退出

我们创建子进程的目的,说白了就是让子进程为我们干活,干完活后会正常退出(exit),也有可能没干完异常退出(abort,或ctrl+c)。因此我们需要等待子进程退出,并收集退出状态。子进程退出状态不被收集会编程僵尸进程。

c 复制代码
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

int main(){
        //pid_t getpid(void);
        pid_t pid;
        int cnt = 0;

        pid = vfork();

        if(pid > 0){
                while(1){
                        printf("%d\n",cnt);
                        printf("this is father process,father pid is:%d\n",getpid());
                        sleep(1);
                }
        }else if(pid == 0){
                while(1){
                        printf("this is son process,son pid is:%d\n",getpid());
                        sleep(1);
                        cnt++;
                        if(cnt == 3){
                                exit(0);
                        }
                }
        }

        return 0;
}

在这段代码中,我们只是调用exit(0)退出进程,而没有收集退出状态,因此这个进程会变为僵尸进程,我们可以通过查看进程状态来观察:

this is son process,son pid is:14192

this is son process,son pid is:14192

this is son process,son pid is:14192

3

this is father process,father pid is:14191

3

this is father process,father pid is:14191

CLC 14191 0.0 0.0 4160 428 pts/0 S+ 10:56 0:00 ./myPro

CLC 14192 0.0 0.0 0 0 pts/0 Z+ 10:56 0:00 [myPro]

CLC 14194 0.0 0.0 13588 940 pts/4 S+ 10:56 0:00 grep --color=auto myPro

父进程id为14191 状态为S+说明正在运行,而子进程id为14192,状态为Z+说明是僵尸进程。

wait函数

因此我们需要调用wait函数来收集退出状态,防止子进程变为僵尸进程:

#include <sys/types.h>

#include <sys/wait.h>

*pid_t wait(int status); //参数是一个指针,是一个地址

在父进程中调用wait函数,会让子进程先退出后父进程在开始运行。

status参数

NULL

当我们不关心子进程的退出码时,直接wait(NULL);即可

在父进程中加入wait(NULL);运行后结果:

this is son process,son pid is:14259

this is son process,son pid is:14259

this is son process,son pid is:14259

3

this is father process,father pid is:14258

3

this is father process,father pid is:14258

子进程的pid为14259,父进程pid为14258,之后去检查子进程的运行状态:

CLC 14258 0.0 0.0 4160 428 pts/0 S+ 11:08 0:00 ./myPro

CLC 14261 0.0 0.0 13588 936 pts/4 S+ 11:08 0:00 grep --color=auto myPro

可以看到子进程已经退出,不是僵尸进程了。

非空

子进程的退出状态放在它所指向的地址中。

WIFEXITED(status)

此时我们需要调用特定的宏去解析,如果为正常终止子进程返回的状态,则为真(1).对于这种情况可执行WEXITSTATUS(status),取子进程传送给exit,_exit或_Exit参数的低8位。

c 复制代码
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

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

        pid = fork();

        if(pid > 0){
       	 		wait(&status);
                printf("child process quit,WIFEXITED=%d,WEXITSTATUS=%d\n",WIFEXITED(status),WEXITSTATUS(status));
                while(1){
                        printf("this is father process,father pid is:%d\n",getpid());
                        sleep(1);
                }
        }else if(pid == 0){
                while(1){
                        printf("this is son process,son pid is:%d\n",getpid());
                        sleep(1);
                        cnt++;
                        if(cnt == 3){
                                exit(3);
                        }
                }
        }

        return 0;
}

运行结果:

this is son process,son pid is:14392

this is son process,son pid is:14392

this is son process,son pid is:14392

child process quit,WIFEXITED=1,WEXITSTATUS=3

this is father process,father pid is:14391

WIFSIGNALED(status)

若为异常终止子进程返回的状态,则为真(接到一个不捕捉的信号)。对于这种情况,可执行WTERMSIG(status),取使进程终止的信号编号。

waitpid

wait与waitpid的区别:wait使调用者阻塞,waitpid有一个选项,可以使调用者不阻塞

*pid_t waitpid(pid_t pid, int status, int options);

pid_t pid

pid == -1 等待任一子进程。就这一方面而言,waitpid和wait等效

pid > 0 等待其进程id与pid相等的子进程

通常使用pid > 0在父进程中,由fork创建的子进程的pid号就等于父进程fork的返回值

pid == 0 等待其组id等于调用进程组id的任一子进程

pid < -1 等待其组id等于pid绝对值的任一子进程

int options常量参数

WCONTINUED :若实现支持作业控制,那么由pid指定的任一子进程在暂停后已经继续,但其状态尚未报告,则返回其状态。
WNOHANG :若由pid指定的子进程并不是立即可用的,则waitpid不阻塞,此时返回值为0
WUNTRACED:若某实现支持作业控制,而由pid指定的任一子进程已处于暂停状态,并且其状态自暂停以来还未报告过,则返回其状态。

使用wait时会阻塞父进程,先运行子进程。如果我们希望不阻塞父进程,可以将options改为WNOHANG:

c 复制代码
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

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

        pid = fork();

        if(pid > 0){
                while(1){
                        //wait(&status);
                        waitpid(pid,&status,WNOHANG);
                        printf("child process quit,WIFEXITED=%d,WEXITSTATUS=%d\n",WIFEXITED(status),WEXITSTATUS(status));
                        printf("this is father process,father pid is:%d\n",getpid());
                        sleep(1);
                }
        }else if(pid == 0){
                while(1){
                        printf("this is son process,son pid is:%d\n",getpid());
                        sleep(1);
                        cnt++;
                        if(cnt == 3){
                                exit(3);
                        }
                }
        }

        return 0;
}

运行结果:

this is father process,father pid is:14535

this is son process,son pid is:14536

this is father process,father pid is:14535

this is son process,son pid is:14536

两个进程同时运行,不会发生阻塞的情况。

但是此时我们查看进程运行状态可以发现,虽然我们调用waitpid读取的子进程退出状态,但是子进程仍然是Z+僵尸进程。因此就目前的学习情况来说,还是使用wait来收集退出状态比较好,在未来waitpid会有他自己的应用。

孤儿进程

父进程如果不等待子进程退出,在子进程之前就结束了自己的生命,此时子进程叫做孤儿进程。

linux为了避免系统存在过多孤儿进程,init进程(进程id=1)收留孤儿进程,变成孤儿进程的父进程。

我们可以使父进程比子进程先结束,让父进程只执行一段printf函数而子进程执行三次,打印观察子进程的父进程id(通过getppid()读取父进程的pid)的变化:

c 复制代码
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

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

        pid = fork();

        if(pid > 0){
                printf("this is father process,father pid is:%d\n",getpid());
        }else if(pid == 0){
                while(1){
                        printf("this is son process,son pid is:%d,my father pid is:%d\n",getpid(),getppid());
                        sleep(1);
                        cnt++;
                        if(cnt == 3) exit(0);
                }
        }

        return 0;
}

运行结果:

this is father process,father pid is:15583

this is son process,son pid is:15584,my father pid is:15583

this is son process,son pid is:15584,my father pid is:1

this is son process,son pid is:15584,my father pid is:1

可以看到父进程的pid为15583,最开始子进程的父进程pid还是15583,此时父进程还没有结束,之后父进程比子进程先结束了,那么子进程就变成了孤儿进程,被init进程收留,init进程的pid为1.

相关推荐
摸鱼也很难1 小时前
Docker 镜像加速和配置的分享 && 云服务器搭建beef-xss
运维·docker·容器
watermelonoops1 小时前
Deepin和Windows传文件(Xftp,WinSCP)
linux·ssh·deepin·winscp·xftp
woshilys2 小时前
sql server 查询对象的修改时间
运维·数据库·sqlserver
疯狂飙车的蜗牛2 小时前
从零玩转CanMV-K230(4)-小核Linux驱动开发参考
linux·运维·驱动开发
恩爸编程3 小时前
探索 Nginx:Web 世界的幕后英雄
运维·nginx·nginx反向代理·nginx是什么·nginx静态资源服务器·nginx服务器·nginx解决哪些问题
Michaelwubo4 小时前
Docker dockerfile镜像编码 centos7
运维·docker·容器
远游客07135 小时前
centos stream 8下载安装遇到的坑
linux·服务器·centos
马甲是掉不了一点的<.<5 小时前
本地电脑使用命令行上传文件至远程服务器
linux·scp·cmd·远程文件上传
jingyu飞鸟5 小时前
centos-stream9系统安装docker
linux·docker·centos
好像是个likun5 小时前
使用docker拉取镜像很慢或者总是超时的问题
运维·docker·容器