大家好,我是仲一。
之前有读者找我模拟面试,我问了一道题:
int main()
{
fork();
fork() && fork() || fork();
fork();
}
不算 main 进程本身,一共创建了多少个新进程?
对方想了挺久,最后给了一个数字。我问怎么算出来的,说不太清楚。这不怪他——这道题同时考两个知识点,漏一个就算不对。
这道题是兆易创新校招笔试的原题。借它把 fork 和短路运算一次说清楚。
fork 的基本规则
fork 调用一次返回两次。父进程里返回子进程的 PID,子进程里返回 0。返回负数说明创建失败。
pid_t pid = fork();
if (pid == 0) {
// 子进程
} else if (pid > 0) {
// 父进程
}
短路规则
&& 左边是假,右边就不看了。左边是真,才继续看右边。
|| 左边是真,右边就不看了。左边是假,才继续看右边。
解这道题就靠这两条。
逐行推导
拆成三行来看。
第 1 行:fork()
进程翻倍。1 个变 2 个,新增 1 个。
第 2 行:fork() && fork() || fork()
这是核心。每个进程执行到这行时,都要按短路规则算。
第一个 fork 跑完,每个进程变成两个。一个返回 0(子进程),一个返回非 0(父进程)。
返回非 0 的进程,在 && 语境下算"真",继续执行第二个 fork。第二个 fork 再一分为二。
返回 0 的进程,在 && 语境下算"假",&& 短路了,第二个 fork 不执行。但表达式还没完——后面还有 ||。|| 左边是假,所以第三个 fork 必须执行。
这里容易想错的是:第二个 fork 产生的子进程里,fork 返回 0。这个子进程里的 && 也是假,所以它也会去执行第三个 fork。
走完这条链,第二行三个 fork 总共新增了 8 个进程。
第 3 行:fork()
到这一行一共有 10 个进程(原始 1 + 第一行 1 + 第二行 8)。每个再 fork 一次,新增 10 个。
加起来:1 + 8 + 10 = 19。
常见的错误答案
有人算 30,有人算 24。
30 是把中间行当成三个独立 fork 来算,没考虑短路。24 是少算了一层。
不信的话,把代码在 Linux 上跑一遍,数一下进程数就清楚了。
面试官可能会追问
fork 之后父子进程谁先执行? 不确定,取决于调度器。
子进程继承了哪些东西? 文件描述符、信号处理方式、环境变量——但地址空间是自己的(写时复制)。
怎么用 fork 创建固定数量的子进程? 配合循环,fork 返回 0 时 break 出来,不然子进程会继续 fork。
题目聊完了,思路应该清楚了。
你第一次算出来是几个?留言说说。
end
135