You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

fork()与exec()创建进程:两段代码执行逻辑解析请求

嘿,我来帮你把这两段代码的执行逻辑拆解得明明白白,重点讲清楚fork、wait和execlp在这里的作用~

代码1的执行逻辑

先看原代码(补全了缺失的status变量,否则编译会报错,不影响核心逻辑):

int child_pid;
int status;
for (int i = 0; i < 3; i++) {
    child_pid = fork();
    if (child_pid == 0) {
        sleep(10);
    } else {
        wait(&status);
    }
}
execlp("sleep","sleep","20",(char*)NULL);

首先得记住fork的核心特性:调用一次,返回两次。父进程会拿到新创建子进程的PID(非0值),子进程则拿到0,而且父子俩都会从fork的下一行代码继续往下跑——这是理解所有fork代码的关键!

这段代码的循环会执行3次(i=0、1、2),我们一步步捋:

  • 初始父进程P0,第一次循环(i=0):

    • 执行fork,造出子进程P1。
    • P0拿到P1的PID(非0),进入else分支,调用wait(&status)——这个函数会让P0卡在这里,一直等到P1完全退出才会继续往下走。
    • P1拿到0,进入if分支,sleep10秒。等睡醒后,P1不会直接退出,而是回到循环顶部,i自增到1,满足i<3,继续第二次循环。
  • P1的第二次循环(i=1):

    • P1执行fork,造出子进程P2。
    • P1拿到P2的PID,进入else分支,wait阻塞,直到P2退出。
    • P2拿到0,sleep10秒,睡醒后i自增到2,继续第三次循环。
  • P2的第三次循环(i=2):

    • P2执行fork,造出子进程P3。
    • P2拿到P3的PID,进入else分支,wait阻塞到P3退出。
    • P3拿到0,sleep10秒,睡醒后i自增到3,不满足i<3,循环结束。
  • 循环结束后的收尾:

    • P3循环跑完后,执行后面的execlp(...)——这个函数会把当前进程的所有代码彻底替换掉,变成执行sleep 20的进程,跑20秒后退出。
    • P2的wait会等到P3完全退出(总共10+20=30秒),然后循环结束,也执行execlp,变成sleep20进程,20秒后退出。
    • P1的wait等到P2退出(10+30+20=60秒),循环结束,执行execlp,sleep20后退出。
    • P0的wait等到P1退出(10+60+20=90秒),循环结束,执行execlp,sleep20后退出。

简单说:代码1会生成一串串行的父生子进程链(P0→P1→P2→P3),每个父进程都要等子进程彻底跑完才继续自己的流程,整个流程总耗时是90+20=110秒。

代码2的执行逻辑

原代码如下(同样补全status变量):

int child_pid;
int status;
for (int i = 0; i < 5; i++) {
    child_pid = fork();
    if (child_pid == 0) {
        sleep(1);
    } else {
        wait(&status);
        execlp("sleep","sleep","20",(char*)NULL);
    }
}

这段代码和代码1的核心区别是:execlp被放在了父进程的else分支里,而execlp的特性是一旦执行,就会把当前进程的代码彻底替换,所以父进程在wait之后,会直接变成sleep20进程,再也不会继续循环了!

我们一步步看:

  • 初始父进程P0,第一次循环(i=0):

    • fork造出子进程P1。
    • P0拿到P1的PID,进入else分支:先wait阻塞,直到P1退出;然后立刻执行execlp,变成sleep20进程,跑20秒后退出——所以P0不会再进入循环的下一次迭代。
    • P1拿到0,进入if分支sleep1秒。睡醒后i自增到1,满足i<5,继续第二次循环。
  • P1的第二次循环(i=1):

    • fork造出子进程P2。
    • P1拿到P2的PID,进入else分支:wait阻塞到P2退出,然后execlp变成sleep20,停止循环。
    • P2拿到0,sleep1秒,睡醒后i自增到2,继续循环。
  • P2的第三次循环(i=2):

    • fork造出P3,P2进入else分支,wait后execlp,不再循环;P3sleep1秒后i=3,继续循环。
  • P3的第四次循环(i=3):

    • fork造出P4,P3wait后execlp;P4sleep1秒后i=4,继续循环。
  • P4的第五次循环(i=4):

    • fork造出P5,P4进入else分支:wait阻塞到P5退出,然后execlp变成sleep20。
    • P5拿到0,sleep1秒,睡醒后i自增到5,不满足i<5,循环结束——P5没有后续代码,直接退出。
  • 连锁收尾:

    • P4的wait等到P5退出(1秒),然后execlp sleep20,跑20秒后退出。
    • P3的wait等到P4退出(1+20=21秒),然后execlp sleep20,20秒后退出。
    • P2的wait等到P3退出(1+21+20=42秒),然后execlp sleep20,20秒后退出。
    • P1的wait等到P2退出(1+42+20=63秒),然后execlp sleep20,20秒后退出。
    • P0的wait等到P1退出(1+63+20=84秒),然后execlp sleep20,20秒后退出。

总结:代码2同样是一串串行的父生子进程链,但只有子进程会一路跑完整5次循环;每个父进程在等子进程退出后,立刻就变成sleep20进程,不会再继续创建新的子进程了。

内容的提问来源于stack exchange,提问作者ponikoli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:44:59