进程原语-fork()

fork可以用于进程的创建,在父进程中使用fork()可以创建一个子进程,子进程可以执行fork后面的代码。

默认情况下子进程可以继承父进程的资源,然后执行和父进程一样的操作。创建子进程时,fork内的_CREATE函数将会为子进程申请空间(4G的那个),然后会调用_CLONE函数部分拷贝父进程内核层的数据到子进程的内核层,然后父进程的用户层的数据将会完全拷贝到子进程的用户层。_CLONE执行完毕后,将会把子进程的pid作为返回值给父进程的fork函数,而子进程的fork函数则是0。这样就意味着,同一个fork函数根据进程的不同返回值是不同的,在父进程中这个返回值是子进程的Pid,而在子进程中返回值为0。因此可以根据fork的返回值来进行父子进程的区分。

对于这个返回值的特性,有一个题目让我感到很棘手,做了好久才明白。

下面展示一下这个题目:

fork();

fork()&&fork()||fork();

fork();

当执行完这三条语句,总共有多少个进程?(当我看到第二条语句时,我就意识到了肯定和条件语句短路有关,但是依然做了很久……)

首先回顾一下条件语句的短路情况:

1. a&&b

&&只有两边都是真才取真,如果一边为假则不会执行另一边,在这个例子中,如果a为假,b直接不会被判断。

2. a||b

||只有两边都是假才取假,如果一边为真则不会执行另一边,在这个例子中,如果a为真,b直接不会被判断。

在这个题目中就会用到这个性质,另外一般是从左往右判断,但&&的优先级比||高,不过在这个题目中没有影响。然后就是根据返回值是否为0判断fork()是否执行,是否会创建新进程了。

首先第一行的fork()执行后会产生一个子进程。接下来这两个进程都会执行第二行和第三行,两边的过程是一模一样的,咱们只需要搞清楚一边再*2就得到最后的结果了。

我先以父进程那边为例了,当父进程走到fork()&&fork()||fork()时,首先执行第一个fork(),此时创建出一个进程1

在父进程中此时&&左边的返回值为真,继续执行&&右边的for(),结果发现也为真,那么||右边的fork()就短路不再执行了。&&右边的fork()执行过后就产生一个进程2

这样一来,在父进程中第二条语句已经执行完毕,接下来咱们看看其他的子进程在第二条语句会发生什么。

首先就是刚才的进程1,在进程1中,&&左边的fork()返回值为0,因为他是这个fork出来的子进程,这样根据短路,进程1就要去执行||右边的fork()了,因此会产生一个进程3。此时进程1也执行完了第二条语句。

在看一下刚才的进程2,在进程2中,&&左边的fork()返回值是父进程的返回值,因此为真,&&右边的返回值是0,因为进程2是这个fork出来的,因此进程二不会短路要去执行||右边的fork,这样以来就会产生一个新的进程4。此时进程2也执行完了第二条语句。

而进程3和进程4是直接从第三条语句开始执行的,那么现在就是父进程和四个子进程都执行第三条语句,最后一共有10个进程。

这是一边的,另一边的情况也是这样,所以总共有20个进程。

进程原语-fork()_第1张图片

我将其中一侧的流程图画了一下。另一侧和这个是一摸一样的。其中标红部分就是最后的进程,我对每个部分的执行以及表达式的值都有一些标记。

进程原语-fork()_第2张图片

进程原语-fork()_第3张图片我也验证了一下,确实是20个进程。

这道题除了fork的一些特性外,还对逻辑运算的短路进行了考察,一开始接触的时候真的感觉不太好做,我还以为只要是子进程中的fork返回值都是0,因此在第一次fork出来的子进程后面的执行弄错了。不过现在再做这个题应该是可以做对的了。

你可能感兴趣的:(linux,服务器,运维)