问题描述

代码如下(不算 main 进程本身,问总共创建了多少个子进程):

int main(int argc, char* argv[])
{
    fork();
    fork() && fork() || fork();
    fork();
}

选项:A.18 B.19 C.20 D.21


先把结论放前面

  • 程序最终一共会有 20 个进程(包含最初的 main 进程)
  • 因为题目要求“不算 main 进程本身”,所以创建的子进程数为:20 - 1 = 19
  • 正确选项:B.19

必备知识点:fork 返回值 + C 里的真假

1)fork() 做了什么?

fork() 会复制当前进程,产生一个子进程:

  • 父进程中,fork() 返回 子进程 pid(>0)
  • 子进程中,fork() 返回 0
  • 失败返回 -1(本题默认不考虑失败)

2)C 语言中真假如何判断?

  • 0 表示 假(false)
  • 非 0 表示 真(true)

所以:

  • 父进程里 fork() 的返回值为真
  • 子进程里 fork() 的返回值为假

本题的灵魂:&& / || 的短路求值 + 优先级

1)优先级

在 C 语言里:&& 的优先级 高于 ||

因此这句:

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

等价于:

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

2)短路规则(务必牢记)

  • A && B:如果 A 为假,则 不再计算 B
  • A || B:如果 A 为真,则 不再计算 B
  • 运算从左到右求值

逐行计算:进程数怎么变

我们按“每一行执行后,进程数乘几”来算。

第 1 行:fork();

每个进程执行一次 fork(),都会一分为二:

  • 1 个进程 → 2 个进程
  • 也就是:×2

第 2 行:(fork() && fork()) || fork()

这一行最容易错。关键点:不同分支会不会继续执行后面的 fork(),取决于短路。

下面用“一个进程进入这一行”为例,算这一行最终会变成多少个进程。

可视化流程图(Mermaid)

父: pid为正 真

子: 返回0 假

父: pid为正 真

子: 返回0 假

进入表达式

fork1

进入 AND 右侧

AND 短路,进入 OR 右侧

fork2

左侧为真,OR 短路

左侧为假,执行 fork3

fork3

fork3

结束

结束

结束

用“分支计数法”数进程

设进入这一行前只有 1 个进程:

  1. 先执行第一个 fork()(记作 F1)

    • 变成 2 个进程
    • 父进程:F1 返回真
    • 子进程:F1 返回假
  2. 对父进程(F1 为真):

    • 需要继续算 && 右侧,于是执行第二个 fork()(F2)
    • F2 又把该父分支变成 2 个进程
      • F2 父:true && true 为真 → || 短路 → 不执行第三个 fork
      • F2 子:true && false 为假 → 进入 || 右侧 → 会执行第三个 fork(F3),再分裂一次
  3. 对子进程(F1 为假):

    • && 短路:第二个 fork() 不执行
    • 直接进入 || 右侧:会执行第三个 fork()(F3),再分裂一次

把最终的进程数列一下(从 1 个进程进入该行开始):

  • F1 父 + F2 父:1 个(不会执行 F3)
  • F1 父 + F2 子:会执行 F3 → 2 个
  • F1 子:会执行 F3 → 2 个

总计:1 + 2 + 2 = 5

所以这一行的效果是:

  • ×5

经验化记忆:(fork() && fork()) || fork() 每个进入的进程最终会变成 5 个。


第 3 行:fork();

最后一行再次每个进程一分为二:

  • ×2

汇总:最终进程数与创建进程数

设最开始只有 1 个 main 进程:

语句 乘法因子 执行后总进程数
初始 - 1
fork(); ×2 2
(fork() && fork()) fork(); ×5 10
fork(); ×2 20
  • 最终总进程数(包含 main):20
  • 创建的子进程数(不算 main):20 - 1 = 19

常见坑位总结

  1. 忘了 && 优先级高于 ||,没加括号就按错误方式理解表达式
  2. 忘了短路:以为每个分支都会把三个 fork() 全执行
  3. 忘了题目“不算 main 进程本身”:最终进程数要再减 1

小结

这类题的核心不是“fork 有多难”,而是:

  • fork() 在父子进程中的返回值真假不同
  • && / || 的短路会让某些分支“跳过 fork”,从而改变进程增长倍率
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐