父进程中getpid()值与子进程中getppid()值不相同的问题及解释
使用fork()
创建一个新的子进程,并调用getpid()
与getppid()
查看父子进程之间的pid
的关系。示例代码如下:
#include "common.h"int main() {pid_t pid;if ( (pid = fork()) < 0 ) {perror("fork()");exit(1);}if ( pid ) {printf("parent process <%d>--><%d>--><%d>\n", getppid(), getpid(), pid);} else {printf("child process <%d>--><%d>\n", getppid(), getpid());}return 0;}
输出结果为:
parent process <>--><11595>--><11596>child process <1387>--><11596>
按照父子进程之间的关系,应该有这样的结论:子进程的父进程pid
应该等于实际父进程的pid
,即在子进程中调用getppid()
得到的值应该和父进程中调用getpid()
得到的值相同。
此时输出结果中,父进程中查到子进程的pid = 11596
,这和子进程中的11596
值相同,是没问题的,但子进程中ppid
不是11595
而是1387
,这是为什么呢?
使用ps
命令查看系统中的进程,可以看到1387
对应的是systemd
。
ubuntu@ubuntu:~/Desktop/linux$ ps -ePID TTYTIME CMD1387 ? 00:00:00 systemdubuntu@ubuntu:~/Desktop/linux$ ps -e | grep "systemd"1 ? 00:00:03 systemd1054 ? 00:00:00 systemd1387 ? 00:00:00 systemd
先来了解一下什么是systemd
Linux 操作系统的启动首先从 BIOS 开始,然后由 Boot Loader 载入内核,并初始化内核。内核初始化的最后一步就是启动 init 进程。这个进程是系统的第一个进程,PID 为 1,又叫超级进程,也叫根进程。它负责产生其他所有用户进程。所有的进程都会被挂在这个进程下,如果这个进程退出了,那么所有的进程都被 kill 。如果一个子进程的父进程退了,那么这个子进程会被挂到 PID 1 下面。
历史上,Linux 的启动一直采用 init 进程,这种方法有两个缺点。一是启动时间长。init 进程是串行启动,只有前一个进程启动完,才会启动下一个进程。二是启动脚本复杂。init 进程只是执行启动脚本,不管其他事情。脚本需要自己处理各种情况,这往往使得脚本变得很长。
Systemd 就是为了解决这些问题而诞生的。它的设计目标是,为系统的启动和管理提供一套完整的解决方案。根据 Linux 惯例,字母d是守护进程(daemon)的缩写。Systemd 这个名字的含义,就是它要守护整个系统。使用了 Systemd,就不需要再用 init了。Systemd 取代了 initd,成为系统的第一个进程(PID 等于 1),其他进程都是它的子进程。
综上所述,因为测试代码执行的环境中只有一个CPU,所以子进程要等待父进程执行结束后才能执行(示例代码父进程的任务可以在一个时间片内执行完,否则在下次调度时父子进程调度顺序不确定),而父进程结束执行后,子进程会变为僵尸进程挂在systemd
下。如果执行环境中存在多个CPU,运行相同的代码,会看到不一样的结果,父进程中getpid()
值与子进程中getppid()
值会出现相同的情况。
问题遗留:为什么子进程中的systemd
的pid
不是1,使用ps
查看时为什么有多个systemd
进程?