1.Fork()函数的简单介绍
fork()是一个系统调用,用于创建一个独立于主进程的子进程。创建的这个子进程与主进程基本一致。一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把主进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同,相当于复制了另一个“自己”。虽说如此,但是主进程在调用fork()之前的代码,子进程并没有执行,子进程只是复制了主进程的数据罢了。
2.Fork()函数的返回值
- 在父进程中,fork返回新创建子进程的进程ID;
- 在子进程中,fork返回0;
- 如果出现错误,fork返回一个负值;
通过fork()的返回值我们可以快速地区分主进程和子进程。
3.fork()函数的特性
我们先看一段代码:
1 int main()
2 {
3 pid_t pid;
4 int x = 1;
5
6 pid = Fork();
7 if(pid = 0){/* Child */
8 printf("child : x=%d\n",++x);
9 exit(0);
10 }
11
12 /* Parent */
13 printf("parent : x=%d\n",--x);
14 exit(0);
15 }
这段代码的输出结果是:
parent : x=0
child : x=2
fork()函数具有以下几个特性:
1.调用一次,返回两次
在上面这个例子中,我们调用了一次fork()函数,但是却返回了两个值。
2. 并发执行
如果我们执行多次上面的代码,我们会发现有时候输出顺序会反过来,这是由于主进程和子进程是并发进行的独立进程,内核能够以任意方式交替执行两个进程,因此输出结果完全是随机的。
3. 相同但是独立的地址空间
相同是指子进程与主进程具有相同的用户栈、相同的本地变量值、相同的堆、相同的全局变量值,以及相同的代码。所以在上面的例子中,当fork()在第6行返回时,主进程和子进程中的本地变量x的值都为1。
独立是指主进程和子进程的运行都是独立的。在上面的例子中,由于主进程和子进程是相互独立的,因此主进程和子进程对x所做的任何改变都是独立的,这也就是为什么当主进程和子进程各自调用它们的printf语句时,输出的结果不同了。
4.共享文件
当我们运行这个程序时,我们会发现主进程和子进程都把它们的输出显示在屏幕上,原因是子进程继承了主进程的所有打开文件。
4.fork()函数的简单例子
下面看一段代码:
1 int mian()
2 {
3 int x = 1;
4
5 if(Fork() == 0)
6 printf("p1: x=%d\n",++x);
7 printf("p2: x=%d\n",--x);
8 exit(0);
9 }
我们一起来简单地分析一下。首先,主进程在第5行的时候调用了Fork()函数,这时创建了一个子进程,此时主进程和子进程的x的值都为1;
在子进程中,fork()返回的值为0,调用if下面的printf语句,x先加1,然后输出:p1: x=2;随后执行第二个printf语句,x减1,然后输出:p2: x=1;最后退出。
在主进程中,由于fork()返回的值不为0,所以跳过if,直接执行第二个printf语句,x先减1,然后输出:p2: x=0;最后退出。
因此主进程的输出为:
p2: x=0
子进程的输出为:
p1: x=2
p2: x=1