Linux系统编程进程控制 – fork()
pid_t fork(void);//pid_t为int类型,进行了重载
pid_t getpid();// 获取当前进程的pid值
pid_t getppid(); //获取当前进程的父进程pid值
fork()函数用于创建一个进程,所创建的进程复制父进程的代码段/数据段/BSS段/堆/栈等所有用户空间信息;在内核中操作系统重新为其申请了一个PCB,并使用父进程的PCB进行初始化
1.1 在linux中调用fork()函数子进程返回的父进程pid为1是什么原因
在Linux中调用fork()
函数后,子进程会复制父进程的地址空间和所有资源,包括文件描述符和进程ID等信息。子进程的进程ID(PID)是通过操作系统内核自动生成的,由于进程ID是全局唯一的标识符,因此操作系统不能简单地将父进程的进程ID赋给子进程。
在调用fork()
函数后,父进程和子进程是两个完全独立的进程,它们有各自的进程ID。通常情况下,子进程的进程ID会比父进程的进程ID大1。但是,如果父进程在子进程之前退出了,子进程的父进程ID会被设置为1,这是因为操作系统将所有孤儿进程(即没有父进程的进程)的父进程ID设置为1。因此,如果您在调用fork()
函数后立即退出父进程,子进程的父进程ID就会被设置为1。
#include <stdlib.h> // 包含标准库头文件
#include <stdio.h> // 包含输入输出头文件
#include <unistd.h> // 包含Unix标准头文件
#include <sys/wait.h>
int main(int argc, char *argv[]) { // 主函数
printf("before fork()\n"); // 输出字符串
pid_t pid = fork(); // 创建子进程
if(pid == -1) { // 如果创建子进程失败
perror("fork() error"); // 输出错误信息
exit(1); // 退出程序
} else if(pid == 0) { // 如果是子进程
printf("I am child process, my id = %d, my parent process id = %d\n", getpid(), getppid()); // 输出子进程的ID和父进程的ID
} else if(pid > 0) { // 如果是父进程
wait(NULL); // 等待子进程结束(注释此条语句后发生错误)
printf("I am parent process, my child id = %d, my id is %d, my parent process id = %d\n", pid, getpid(), getppid()); // 输出父进程的ID、子进程的ID和父进程的ID
}
printf("============end of file.\n"); // 输出字符串
return 0; // 返回0,表示程序正常结束
}
注释掉 wait(NULL); // 等待子进程结束
后,其输出为:
I am parent process, my child id = 90569, my id is 90568, my parent process id = 86676
============end of file.
I am child process, my id = 90569, my parent process id = 1
============end of file.
在子进程中返回的父进程为id = 1
,不符合预期id = 90568
要避免该问题,可以在调用fork()
函数后,在父进程中等待子进程执行完毕后再退出,这样就能确保子进程的父进程ID不会被设置为1。
可以使用wait()
或waitpid()
函数等待子进程的结束。这些函数将挂起父进程,直到子进程退出。此时,父进程再调用exit()
函数退出,确保子进程的父进程ID是正确的。
输出:
before fork()
I am child process, my id = 90132, my parent process id = 90131
============end of file.
I am parent process, my child id = 90132, my id is 90131, my parent process id = 86676
============end of file.
1.2 循环创建n个子进程
从上图我们可以很清晰的看到,当 n 为 3 时候,循环创建了(2^n)-1 个子进程,而不是 N 个子进程。需要在循环的过程,保证子进程不再执行 fork ,因此当(fork() == 0)时,子进程应该立即 break;才正确。
#include <stdlib.h> // 包含标准库头文件
#include <stdio.h> // 包含输入输出头文件
#include <unistd.h> // 包含Unix标准头文件
#include <sys/wait.h>
int main(int argc, char *argv[]) { // 主函数
printf("before fork()\n"); // 输出字符串
for(int i = 0; i < 5; i++) {
pid_t pid = fork(); // 创建子进程
if(pid == -1) { // 如果创建子进程失败
perror("fork() error"); // 输出错误信息
exit(1); // 退出程序
} else if(pid == 0) { // 如果是子进程
printf("I am child number %d process, my id = %d, parent process id = %d\n", i+1, getpid(), getppid()); // 输出子进程的ID和父进程的ID
break;
} else if(pid > 0) { // 如果是父进程
wait(NULL); // 等待子进程结束
}
}
printf("============end of file.\n"); // 输出字符串
return 0; // 返回0,表示程序正常结束
}
输出:
before fork()
I am child number 1 process, my id = 90049, parent process id = 90048
============end of file.
I am child number 2 process, my id = 90050, parent process id = 90048
============end of file.
I am child number 3 process, my id = 90051, parent process id = 90048
============end of file.
I am child number 4 process, my id = 90052, parent process id = 90048
============end of file.
I am child number 5 process, my id = 90053, parent process id = 90048
============end of file.
============end of file.