每一个进程都会有一个独一无二的编号,被称为进程标识码,简称PID(Process identifier),它是一个取值从1到32768的正整数。其中1是特殊进程init,其他的进程从2开始依次编号,当32768用完后就从2重新开始。 所谓的init进程,是一个由内核启动的用户级进程,也是系统上运行的所有其他进程的父进程,它会观察其子进程,并在需要的时候启动、停止、重新启动它们,init进程主要用来完成系统的各项配置。init从根文件系统目录里的/etc/inittab文件获取所有信息,通常在根文件系统的/***in或/bin目录下,它负责在系统启动时运行一系列程序和脚本文件,同时init进程也是所有进程的发起者和控制者。内核启动之后,便开始调用init进程来进行系统各项配置,该进程对于Linux系统正常工作是十分重要的。 一个进程(父进程)可以通过调用fork()函数创建一个新的进程,这个新进程称为该进程的子进程。fork()函数的原型是: #include pit_t fork(void) 在使用fork()函数时,记得在代码中添加头文件#include 。 fork()函数几乎完整地复制了父进程,子进程在许多属性上与父进程相同,执行的代码也完全相同,但是子进程与父进程则有着不同的PID编号、独立的数据空间和进程描述符。 如果调用fork()函数成功,fork()函数有两个返回值,在父进程和子进程中返回的是不同的值,父进程中返回的是新产生子进程的PID,而子进程中则返回0。若fork()函数调用失败则返回-1。
下面通过一个例程来进一步理解掌握fork()函数,代码如下所示: #include "stdio.h" #include "sys/types.h" #include "unistd.h" int main() { pid_t pid1; pid_t pid2; pid1 = fork(); pid2 = fork(); printf("pid1:%d, pid2:%dn", pid1, pid2); } 在终端下新建一个源代码文件fork.c,添加上述代码后保存,然后利用gcc编译器编译上述代码。 # gedit fork.c # gcc –o fork fork.c 编译后可以在fork.c所在的目录下看到生成的可执行文件fork。运行fork可执行文件。 # ./fork 运行效果如下图所示:
从上图可以看出,该程序一共运行了四个进程,其中父进程的PID为“0”,其他三个进程的PID分别为“2768、2769、2770”。4个进程的产生过程如下图所示:
程序开始运行就创建了进程A,当代码执行到pid1=fork()处时,父进程A创建了子进程B,此时就出现了两个进程,子进程B复制了父进程A的全部资源后,父进程A和子进程B都在pid2=fork()处继续执行,之后父进程A又创建了子进程C,子进程B也创建了子进程D,这样便产生了全部4个进程。 程序中pid1、pid2的PID号打印信息是不确定的,如果程序再执行一遍后其PID均有所改变。另外,在执行fork()函数后是先执行父进程还是先执行子进程也是不固定的,这是由程序运行的过程中内核所使用的调度算法来决定的。如果要求父子进程之间的执行是按照一定顺序进行就需要使用进程间同步威廉希尔官方网站
。
|