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.

相关推荐
傻啦嘿哟30 分钟前
Python正则表达式:用“模式密码“解锁复杂字符串
linux·数据库·mysql
浪裡遊2 小时前
Linux常用指令
linux·运维·服务器·chrome·功能测试
SugarPPig2 小时前
PowerShell 查询及刷新环境变量
服务器
段ヤシ.3 小时前
银河麒麟(内核CentOS8)安装rbenv、ruby2.6.5和rails5.2.6
linux·centos·银河麒麟·rbenv·ruby2.6.5·rails 5.2.6
深夜情感老师5 小时前
centos离线安装ssh
linux·centos·ssh
我的作业错错错5 小时前
搭建私人网站
服务器·阿里云·私人网站
王景程5 小时前
如何测试短信接口
java·服务器·前端
微网兔子6 小时前
伺服器用什么语言开发呢?做什么用什么?
服务器·c++·后端·游戏
夸克App7 小时前
实现营销投放全流程自动化 超级汇川推出信息流智能投放产品“AI智投“
运维·人工智能·自动化
Rainbond云原生7 小时前
83k Star!n8n 让 AI 驱动的工作流自动化触手可及
运维·人工智能·自动化