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.

相关推荐
a_安徒生13 分钟前
linux安装TDengine
linux·数据库·tdengine
追风赶月、20 分钟前
【Linux】线程概念与线程控制
linux·运维·服务器
小字节,大梦想22 分钟前
【Linux】重定向,dup
linux
CP-DD34 分钟前
Docker 容器化开发 应用
运维·docker·容器
blessing。。1 小时前
I2C学习
linux·单片机·嵌入式硬件·嵌入式
2202_754421542 小时前
生成MPSOC以及ZYNQ的启动文件BOOT.BIN的小软件
java·linux·开发语言
努力的悟空2 小时前
国土变更调查拓扑错误自动化修复工具的研究
运维·自动化
运维&陈同学2 小时前
【zookeeper03】消息队列与微服务之zookeeper集群部署
linux·微服务·zookeeper·云原生·消息队列·云计算·java-zookeeper
旦沐已成舟3 小时前
DevOps-Jenkins-新手入门级
服务器
周末不下雨3 小时前
win11+ubuntu22.04双系统 | 联想 24 y7000p | ubuntu 22.04 | 把ubuntu系统装到1T的移动固态硬盘上!!!
linux·运维·ubuntu