popen后台执行进程问题

本文最后更新于:2025年11月19日 下午

popen里面使用&后台进程问题

这个例子可以加深对linux下fork,文件等的理解

直接进入主题,如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>

int main(int argc, char *argv[])
{
char line[128];
FILE *fp = popen("ping 127.0.0.1 &", "r");
if(!fp){
perror("popen");
return -1;
}

# 参数个数控制是否获取输出
if(argc == 2){
while(fgets(line, sizeof(line), fp)){
printf("== %s\n", line);
}
}
pclose(fp);
return 0;
}

问题

分别以./a.out./a.out get运行结果是怎样?

  • ping能在后台运行吗?
  • a.out会立即退出吗?
  • a.out能捕获到ping输出吗?

答案

(1)以 ./a.out 运行,ping不能再后台运行,a.out也会立即退出。
(2)以 ./a.out get运行,ping能在后台运行,a.out可以捕获到ping输出,a.out不会立即退出。

分析

原理

通过strace跟踪系统调用,分析如下:
popen原理
(1) 创建管道
(2)fork
(3)(子进程)将管道描述符dup到标准输入输出上
(4)(子进程)exec程序
(5)(父进程)(这是pclose调用)wait子进程

命令行程序后加&
fork两次,然后子进程退出,孙子进程运行命令行程序。
注意:fork的过程中,并没有去操作描述符

过程

先分析这个过程:以 ./a.out 运行,ping不能再后台运行,a.out也会立即退出。

(1)由于是后台运行ping,所以pclose会很快收到子进程退出,然后返回,a.out便退出了。注意:这是popen创建的管道读端便关闭了。
(2)ping程序运行时,标准输出为a.out的管道写端描述符。当ping程序输出时,会失败,因为a.out已经退出,管道的读已经关闭,会收到SIGPIPE信号,默认动作就是退出。所以ping并不能在后台一直运行。

再分析这个过程:以 ./a.out get运行,ping能在后台运行,a.out可以捕获到ping输出,a.out不会立即退出。

和前面类似,子进程虽然已经退出,但孙子进程ping也随着fork复制了这个管道,子进程关闭管道读只是把引用计数-1,并不会真正关闭读管道,所以a.out进程可以一直读。a.out不退出,ping自然可以向管道输出,持续执行,不会遇到SIGPIPE信号。


popen后台执行进程问题
https://leon0625.github.io/2022/09/07/9c818c7ca46e/
作者
leon.liu
发布于
2022年9月7日
许可协议