每个进程都有一个非负整数的PID,可以通过下面函数返回
#include <unistd.h> //进程ID pid_t getpid(void); //父进程ID pid_t getppid(void);
而调用fork函数可以创建新进程,即子进程;fork被调用一次,就好像copy了一份副本,返回两次,父进程的返回值是子进程的进程ID,子进程的返回值是0
在调用fork之后,子进程获得了父进程的数据空间,堆栈的副本,但这仅仅是副本,父进程和子进程并不共享这些存储空间
可以通过下面小程序来确定fork的两次返回:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(){ int a = 1; pid_t pid; if ((pid = fork()) < 0) { printf("fork error\n"); exit(1); } else if (pid == 0){ printf("fork child process: return %d\n", pid); ++a; } else { printf("fork parent process: return %d\n", pid); --a; } printf("process pid %d: a = %d\n", getpid(), a); return 0; }
else if里fork返回的pid为0,应该是子进程;假如为其它正数,就是父进程,这里直接将这个正数pid打印出来;最终再将父子进程所在的pid都打印出来,确认fork父进程返回的正数即是子进程的进程ID
编译运行一下,结果:
fork child process: return 0 process pid 4608: a = 2 fork parent process: return 4608 process pid 4000: a = 0
从结果可以看到子进程的进程ID为4608,因为子进程ID是在else if里printf输出之后打印的;而父进程fork的返回值也是4608,可见fork父进程返回的正数的确是子进程的进程ID,而子进程返回0
将可执行程序再次运行一下,结果发生了改变:
fork parent process: return 1356 fork child process: return 0 process pid 1608: a = 0
process pid 1356: a = 2
但是不论怎么变,上面一段结果不会改变,变得仅仅是父进程和子进程的打印顺序,也就是说fork之后父进程和子进程的执行顺序是不确定的,这取决于内核的调度算法,如果需要他们相互同步,则需要进程间通信