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后退出。
- P3循环跑完后,执行后面的
简单说:代码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
相关产品推荐
相关产品推荐

