-
什么是fork()
fork()系统调用用于创建新进程,新创建的进程为子进程,调用fork()并创建新进程的进程是父进程。fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,这俩个进程默认完成同样的功能,但如果初始参数和传入的变量不同,俩个进程也可以完成不同的功能。
父子进程运行的时间: 子进程和父进程是同时执行的。但是输出没有固定的顺序,有可能父进程先输出,也有可能子进程先输出。 -
调用fork()发生了什么
子进程创建后,系统会给子进程分配资源,然后把原来的进程的所有值都复制到新的子进程中,只有少数值与原来的进程的值不同;其实就是父进程的一份副本。但是子进程和父进程驻留在不同的内存空间上。这些内存空间具有相同的内容,并且一个进程执行的任何操作都不会影响其他进程。 -
C语言中的fork()
fork()不需要参数,一次调用fork()会返回俩个返回值(在父进程与子进程中分别返回)
-
fork()的返回值
负值: 创建子进程失败。
失败原因:
1)当前的进程数已经达到了系统规定的上限,这时 errno 的值被设置为 EAGAIN。
2)系统内存不足,这时 errno 的值被设置为 ENOMEM。零: 返回到新创建的子进程。
正值: 返回父进程,该值包含新创建的子进程的进程ID。(父进程中返回子进程 ID)pid_t
,为无符号整型。 -
fork()的头文件说明
#include <sys/types.h>
#include <unistd.h>
-
fork()的定义
语法:
pid_t fork(void);
使用fork()时,<sys / types.h>
可用于进程ID的类型pid_t
,因为pid_t
在<sys / types.h>
中定义;
头文件<unistd.h>
是定义fork()的地方,因此必须将它包含在程序中以使用fork();
返回类型在<sys / types.h>
中定义,fork()调用在<unistd.h>
中定义, 因此,需要在程序中包含两者以使用fork()系统调用。
- fork()调用示意图
实例1.
1 #include <stdio.h>
2 #include <unistd.h>
3
4 void Print(){
5 printf("hello world!!!\n");
6 }
7
8 int main(){
9 fork();
10 Print();
11
12 return 0;
13 }
输出效果:
5. fork()调用过程:
用代码强化fork()的调用过程:
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <sys/types.h>
4
5 int main(){
6 pid_t pid = fork();
7 int count = 0;
8 if(pid < 0){ //返回值为负数,调用fork失败
9 printf("fork failed");
10 }else if(pid > 0){ //返回值大于0,该值包含新创建子进程的进程ID
11 printf("我是父进程,进程号为:%d\n", getpid());
12 count++;
13 }else{ //返回值==0,返回到新创建的子进程
14 printf("我是子进程,进程号为:%d\n", getpid());
15 count++;
16 }
17 printf("输出count的值:%d\n", count);
18 return 0;
19 }
输出效果:
- 练习:
我相信通过上面的例子,我们已经对fork()有了一定的认识了,那么我们来做一个练习吧:
1 #include <stdio.h>
2 #include <unistd.h>
3
4 int main(){
5 fork(); //L1(标签值)
6 fork(); //L2
7 fork(); //L3
8 printf("hello world!!!\n");
9 return 0;
10 }
输出:
总共打印了8次,也就是创建了8个进程,进程总数= 2^n其中n是fork系统调用的数量。所以这里n = 3, 2^3 = 8
(新的子进程和原始进程组成)
分析代码:
L1
/ \
L2 L2
/ \ / \
L3 L3 L3 L3