C程序如何不等待system()执行?添加&无效的原因及解决办法
问题解答:为什么
system("cmd &")仍显阻塞,以及非阻塞的替代方案 首先咱们先拆解你遇到的问题根源,再给出可行的解决办法:
为什么加&后Area-C2还是要等Area-C1执行完?
你可能以为命令末尾加&就能让system()立刻返回,但实际上**system()函数的设计逻辑就是会等待它启动的shell进程终止**,具体流程是:
system()会先fork一个子进程,让这个子进程运行/bin/sh -c "你的命令"- 当你在命令后加
&,shell会把目标命令放到后台运行,但shell本身会立刻退出 - 这时候
system()会等待shell进程结束(这一步其实很快),然后返回 - 但你的Area-C1是循环1000次调用
system(),哪怕每次调用只花几毫秒,1000次累加起来也会让程序停在Area-C1一段时间,看起来就像Area-C2在等Area-C1执行完——但本质上不是在等后台的command执行,而是在等1000次system()调用本身完成。
如果你的场景需要C程序完全不等待任何子进程(包括shell),那就要放弃system(),改用更底层的fork()+exec()组合。
非阻塞的替代方案:直接使用fork()和exec()系列函数
system()之所以会阻塞,是因为它主动调用了waitpid()等待子进程。如果手动fork子进程,在子进程中执行命令,父进程不等待子进程,就能实现真正的非阻塞。
把你的代码修改成这样即可:
#include <stdio.h> #include <unistd.h> #include <sys/wait.h> #include <errno.h> #define N1 0 #define N2 1000 int main() { int i = 0, j = 0; /* Area - C1 */ for (i = N1; i < N2; i++) { pid_t pid = fork(); if (pid == -1) { // 处理fork失败的情况 perror("fork failed"); continue; } else if (pid == 0) { // 子进程:执行目标命令,这里用execlp示例 // exec系列函数成功则不会返回,失败才会走到后续代码 execlp("command", "command", (char*)NULL); // 走到这里说明exec失败 perror("execlp failed"); _exit(1); // 子进程必须退出,不能回到主流程 } // 父进程:不等待子进程,直接继续循环 } /* Other codes */ { /*Area - C2;*/ /*Area - C3;*/ } // 可选:非阻塞清理僵尸进程(避免子进程结束后残留资源) int status; while (waitpid(-1, &status, WNOHANG) > 0); return 0; }
代码说明:
fork()创建子进程,父进程得到子进程ID,子进程返回0- 子进程用
execlp()执行命令(第一个参数是命令名,第二个是argv[0],最后必须以NULL结尾) - 父进程不调用
wait()或waitpid(),所以会直接继续执行,完全不等待子进程完成 - 若担心僵尸进程(子进程结束后父进程未清理),可以在后续代码中用
waitpid(-1, &status, WNOHANG)非阻塞清理,不会影响Area-C2的执行
额外注意事项
- 如果命令需要传递参数,比如
command arg1 arg2,execlp要写成:execlp("command", "command", "arg1", "arg2", (char*)NULL) - 对比
system(),fork()+exec()的方式更灵活,但需要自己处理错误情况(比如fork失败、exec失败) - 若需要用到shell的特性(如管道、通配符),可以让子进程执行shell:
execlp("/bin/sh", "sh", "-c", "command arg1 &", (char*)NULL)——此时shell仍会在启动后台命令后立刻退出,父进程依然无需等待
内容的提问来源于stack exchange,提问作者Ritu
相关产品推荐
相关产品推荐

