在 fork() 函数首先来看下fork() 函数,其作用是创建子进程。头文件与函数原型如下 #include <unistd.h> // 参数: void // 返回值: pid_t 创建的子进程ID pid_t fork(void); 返回值:fork() 返回值会返回两次,分别在父进程和子进程中返回。
fork() 示例下面创建一个子进程,来说明父进程与子进程的执行顺序。 #include <unistd.h> #include <stdio.h> int main(){ // 创建进程 pid_t pid = fork(); // 判断当前进程是父进程 还是子进程 if (pid > 0){// 进程号 > 0,即为子进程的进程号,当前为父进程 printf("pid: %d\n", pid); printf("I am parent process, pid: %d, ppid: %d\n", getpid(), getppid()); } else if (pid == 0){// 进程号 == 0,表示当前为子进程 printf("I am child process, pid: %d, ppid: %d\n", getpid(), getppid()); } for (int i = 0; i < 5; i++){ printf("pid: %d, i : %d\n", getpid(), i); sleep(1); } return 0; } 编译执行,可以看到,子进程创建成功,两个进程同时执行,父进程ID 为412552,子进程ID为512553,由于sleep() 函数,使得函数阻塞,所以父进程与子进程交替执行。 父子进程的虚拟地址空间通过 fork函数创建进程后,可以通过返回值判断是父进程还是子进程。对于父进程与子进程如何执行,下面介绍fork函数调用后,父子进程如何执行,在进程中虚拟地址空间中如何体现。 子进程在创建成功后,在子进程中返回 0,从当前位置开始执行,所以 对于虚拟空间地址来说,子进程会拷贝父进程的虚拟地址空间。所以,fork后子进程的用户区与父进程的用户区相同,也会拷贝内核区内容,仅仅是进程的 pid不同。 对于父进程中的栈空间的变量,也会原封不动的拷贝至子进程的栈空间中。但这两个变量互不影响,父进程改变变量不会影响子进程变量。看如下程序展示父子进程中栈空间变量的使用。 #include <unistd.h> #include <stdio.h> int main(){ // 创建进程 pid_t pid = fork(); // 局部变量 int num = 10; // 判断当前进程是父进程 还是子进程 if (pid > 0){// 进程号 > 0,即为子进程的进程号,当前为父进程 printf("I am parent process, pid: %d, ppid: %d\n", getpid(), getppid()); printf("parent process num : %d\n", num); num += 10; printf("parent process num + 10 : %d\n", num); } else if (pid == 0){// 进程号 == 0,表示当前为子进程 printf("I am child process, pid: %d, ppid: %d\n", getpid(), getppid()); printf("child process num : %d\n", num); num += 100; printf("child process num + 100 : %d\n", num); } return 0; } 编译执行,可以看到,父进程中的局部变量
fork函数就介绍到这里了,本篇介绍了创建子进程的过程,理解父子进程间虚拟地址空间的共享与复制。在多线程开发中,可以轻松分析父子进程的执行顺序与内存共享。 |
|