在 linux 中,使用 pipe() 从分叉进程调用 system()
Posted
技术标签:
【中文标题】在 linux 中,使用 pipe() 从分叉进程调用 system()【英文标题】:In linux, calling system() from a forked process with pipe() 【发布时间】:2013-04-24 22:18:15 【问题描述】:我有一个使用 fork() 和 pipe() 的标准程序,目的是在子进程中对第三方程序进行 system() 调用,并将输出重定向到父进程。我发现如果我这样做,不知何故父进程永远无法检测到子进程已关闭管道,因此它永远无法从调用 read() 的 while 循环中退出。
当我将第三方程序的 system() 调用替换为其他一些通用系统调用(如 system("ls -l"))时,问题就消失了。使用影响该程序的 system() 调用第三方程序可能存在哪些潜在问题?
#include <iostream>
#include <fstream>
#include <stdlib.h>//system
#include <sys/wait.h>
int main(int argc, char **argv)
//setup pipe
int pipeid_L1[2];
pipe(pipeid_L1);
pid_t pid_L1;
pid_L1 = fork();
if( pid_L1==-1 )
throw std::logic_error("Fork L1 failed");
else if(pid_L1 ==0)//L1 child process
dup2(pipeid_L1[1],STDOUT_FILENO);//redirect standard out to pipe
close(pipeid_L1[0]); //child doesn't read
system( ... some program ... ); //making the system call to a third party program
close(pipeid_L1[1]);
exit(0);
else
//setup pipe
close(pipeid_L1[1]);
int buf_size=64;
char L1_buf[buf_size];
while( read(pipeid_L1[0],L1_buf,buf_size)) //this while loop never exits if I make the system call to the third party program
... do stuff here ...
exit(EXIT_SUCCESS);
【问题讨论】:
【参考方案1】:问题在于,只有当所有其他进程关闭管道的写入端时,父级才会看到 EOF。有三个相关的进程——你派生的孩子,系统派生和执行的外壳,以及你运行的实际程序。前两个在程序实际退出之前不会关闭管道的末端,因此父级在此发生并且所有进程退出之前不会看到 EOF。
如果您希望父程序在程序关闭其标准输出后立即看到 EOF,而不是等到它退出,您需要使用 exec
而不是 system
来摆脱这些额外的进程。
或者,您可以使用popen
,它会为您完成所有需要的 fork/pipe/exec。
【讨论】:
以上是关于在 linux 中,使用 pipe() 从分叉进程调用 system()的主要内容,如果未能解决你的问题,请参考以下文章
线程和分叉:从 popen()-pipe 读取时 fgetc() 阻塞
C++ Getline 并不总是在 Linux 中的多个分叉进程中获得一致