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.

相关推荐
kebidaixu1 天前
BCU 平台 RS485 驱动适配:从 THVD1406 到 ISO3082
linux
杨浦老苏1 天前
家庭实验室监控仪表盘HomeLab-Monitor
运维·docker·监控·群晖
回忆2012初秋1 天前
【Nginx】原理、配置与运维实战(2)
运维·nginx·策略模式
Urbano1 天前
工装外套全制作流程、工序痛点及自动化设备升级方案
运维·自动化
映翰通朱工1 天前
工业4G网关无公网IP远程运维实战(内网终端异地访问方案)
运维·服务器·网络·安全·智能路由器
洪晓露1 天前
将 rke2 集群证书延长至 10 年
运维·服务器·数据库
谢平康1 天前
解决用 rm 报bash: /usr/bin/rm: Argument list too long错
linux·运维·运维开发
IP老炮不瞎唠1 天前
Python 价格监控如何实现?思路与实用方法分享
运维·服务器·网络
GIS数据转换器1 天前
城市排水生命线安全运行监测平台深度解析
java·运维·人工智能·python·安全·数据挖掘·无人机
睡不醒男孩0308231 天前
CLup 6.x 版本中针对StarRocks 存算一体集群的完整操作手册
java·服务器·网络·clup