最近,我在Linux中学到了一个神奇的函数,名为fork()函数,它的作用是创建进程。它的神奇之处在于调用fork()函数时,系统会创建一个与原来进程几乎完全相同的进程,大致的意思就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事 。就相当于是克隆了一个自己。
先来看一个例子
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
pid_t res=fork();
assert(res!=-1);
if(res==0)
{
printf("hello\n");
exit(0);
}
else
{
printf("world\n");
exit(0);
}
}
大家一定都很好奇结果是什么?那么结果到底是什么呢?
运行结果是
world
hello
在语句res=fork()之前,只有一个进程在执行这段代码,但是在这条语句之后,就变成两个进程在执行了,这两个进程几乎完全相同,将要执行的下一条语句都是if(res<0),为什么两个进程执行的结果会不同呢?这与fork函数的特性有关。
fork函数的神奇之处就在于它仅仅被调用一次,却能够返回两次,它有三种不用的返回值
1)、在新创建的进程即子进程中返回0
2)、在调用fork函数的进程即父进程中返回新创建进程的ID
3)、如果出现错误,fork函数返回一个负值
在fork函数执行完毕后,如果创建进程成功,则出现两个进程,一个父进程和一个子进程。在子进程中,fork函数返回0。在父进程中,fork函数返回子进程的进程号。因此,我们就可以通过fork的返回值来判断当前进程是父进程还是子进程。
父进程和子进程都是从fork函数之后的代码开始执行,那么在条件之外的语句又该如何执行呢?
int main()
{
if(res==0)
{子进程执行}
else
{父进程执行}
父子进程都执行
}
下面请看第二个例子
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
pid_t res=fork();
assert(res!=-1);
if(res==0)
{
printf("你好\n");
}
else
{
printf("中国\n");
}
printf("你好,中国");
}
根据上面介绍的父进程与子进程的执行顺序,结果是 :
中国
你好,中国
你好
你好,中国
之前的例子只是简单的练手,现在重点来了,请看第三个例子
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
int main()
{
int i=0;
for(;i<2:++i)
{
if(fork())
{
printf("A\n");
}
else
{
printf("B\n");
}
}
}
这个例子较之前的两个更加复杂一点,那么这个结果是什么呢?请看下图解析过程
如上图所示,结果为三个A三个B(与顺序无关)。当i=0时,第一个进程创建一个新进程,即黑色箭头产生,结果为黑色字母。当i=1时,第一次创建的两个进程分别创建一个进程,为图中红色箭头,结果为红色结果。至于两个进程谁先创建进程,暂不研究。
本次fork函数讲解就完了,希望大家能多多提出意见。