【问题标题】:popen() alternativepopen() 替代方案
【发布时间】:2011-10-08 07:07:20
【问题描述】:

我的问题是这个问题的扩展:popen creates an extra sh process

动机:

1) 我的程序需要创建一个对文件执行tail 的子程序。我需要逐行处理输出。这就是我使用 popen 的原因,因为它返回 FILE *。我可以轻松地获取单行,做我需要做的事情并打印出来。

popen 的一个问题是你没有得到孩子的 pid(在我的例子中是 tail 命令)。

2) 我的程序在其子程序完成之前不应退出。所以我需要做wait;但是没有pid,我做不到。

如何实现这两个目标?

一个可能的(kludge)解决方案:执行 execvp("tail -f file > tmpfile") 并继续阅读该 tmpfile。不过,我不确定这个解决方案有多好。

【问题讨论】:

    标签: c exec process popen


    【解决方案1】:

    可以使用wait,因为它不想等待PID,而只是等待任何子进程退出。如果您创建了其他子进程,您可以跟踪它们,如果 wait 返回未知 PID,您可以假设它来自您的 popen 进程。

    【讨论】:

    • 如果在某些错误情况下,我需要杀死孩子,我可以这样做吗? (首先会出现这种情况吗?),我只是在大声思考。
    • 假设程序中发生错误并且必须退出,wait 是否会确保子程序在退出主程序之前也被杀死/终止?
    • 你可以create a process group,然后简单地调用kill(getpgrp(), SIGTERM);就会杀死你所有的进程。
    【解决方案2】:

    我不确定您为什么需要孩子的进程 ID。当孩子退出时,您的管道读取将返回一个 EOF。如果您需要终止孩子,只需关闭管道即可。

    【讨论】:

    • 一个孩子可以是永远不会返回的“tail -f”。在这种情况下,当我执行 ctrl-C 时,在我的主程序退出之前,我希望孩子 - “tail -f” 完成。
    【解决方案3】:
    1. 您可以使用pipe,这是exec* 系列和fdopen 的一个功能。这是非标准的,但popen 也是如此。
    2. 您不需要wait。只需阅读到EOF 的管道即可。
    3. execvp("tail -f file > tmpfile") 不起作用,重定向是 shell 的一项功能,您没有在此处运行 shell。即使它有效,这将是一个糟糕的解决方案。假设你已经读到了文件的末尾,但是子进程还没有结束。你是做什么的?

    【讨论】:

    • 1.它们不是非标准的,只是在 C 标准之外。它们是 POSIX 标准的一部分。
    【解决方案4】:

    你为什么不使用 pipe/fork/exec 方法?

    pid_t pid = 0;
    int pipefd[2];
    FILE* output;
    char line[256];
    int status;
    
    pipe(pipefd); //create a pipe
    pid = fork(); //span a child process
    if (pid == 0)
    {
    // Child. Let's redirect its standard output to our pipe and replace process with tail
     close(pipefd[0]);
     dup2(pipefd[1], STDOUT_FILENO);
     dup2(pipefd[1], STDERR_FILENO);
     execl("/usr/bin/tail", "/usr/bin/tail", "-f", "path/to/your/file", (char*) NULL);
    }
    
    //Only parent gets here. Listen to what the tail says
    close(pipefd[1]);
    output = fdopen(pipefd[0], "r");
    
    while(fgets(line, sizeof(line), output)) //listen to what tail writes to its standard output
    {
    //if you need to kill the tail application, just kill it:
      if(something_goes_wrong)
        kill(pid, SIGKILL);
    }
    
    //or wait for the child process to terminate
    waitpid(pid, &status, 0);
    

    【讨论】:

    • 读完后需要close(pipefd[0])吗?还是在kill 之前?
    • 顺便说一下,如果您使用 GLib,则有一个预烘焙的实现,它具有大量功能,而且它可以处理所有错误代码等等。见developer.gnome.org/glib/2.30/glib-Spawning-Processes.html(免责声明:我实现了这个,虽然很多年前)
    • @havoc 或 libHX 的 HXproc_* 系列函数,它不使用带有那么多参数的函数作为 glib。
    • 当然,只是提到我知道的库。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-10-05
    • 2010-09-10
    • 2012-12-05
    • 2013-11-22
    • 2020-11-23
    • 2013-08-07
    • 2015-09-11
    相关资源
    最近更新 更多