【问题标题】:The issue when using popen and pclose使用 popen 和 pclose 时的问题
【发布时间】:2013-03-22 06:23:12
【问题描述】:

我有一个使用popenpclose 的程序:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/wait.h>
int main(void)
{
    FILE *fp = NULL;
    int ret_val = 0;

    fp = popen("ls *", "r");
    if (NULL == fp)
    {
        printf("popen error\n");
        return 1;
    }

    ret_val = pclose(fp);
    if (-1 == ret_val)
    {
        printf("pclose error\n");
        return 1;
    }
    else
    {
        printf("%d,%d,%d\n",ret_val, WIFEXITED(ret_val), WEXITSTATUS(ret_val));
    }
    return 0;
}

程序的输出是:

./test
Broken Pipe
36096,1,141

我的问题是:

  1. 为什么会出现“断管”?
  2. 为什么退出状态码是 141?我认为“ls *”已执行 成功,因此退出状态应为 0。

【问题讨论】:

  • 你了解 Unix 中的管道吗?比如你知道在命令行输入cat /etc/motd | more会发生什么吗?
  • @AhmedMasud: cat /etc/motd | more:cat /etc/motd 的输出将是 more 的输入。这样对吗?谢谢你的建议!
  • @AhmedMasud:我知道,因为有一个“破管道”,“ls *”没有成功执行。所以退出状态是141。但是为什么会出现“断管”呢?我无法找出根本原因。
  • @AhmedMasud:我认为“Broken pipe”是由“ls *”输出的。因为我的程序没有使用 fgets 来获取输出,直接关闭管道。 “ls *”输出“Broken pipe”。对吗?
  • @AnishRam:我同意你的解释。非常感谢!

标签: c shell unix


【解决方案1】:
  • “Broken pipe”由ls 显示,因为 SIGPIPE 信号是 提出。
  • SIGPIPE 被引发,因为ls 试图输出到一个封闭的管道。
  • 管道已关闭,因为您的程序在您的popen() 之后立即调用pclose()

阅读the documentation可以进一步理解pclose的这种行为。基本上,pclose 会:

  1. 关闭由popen() 调用打开的流。
  2. 等待命令终止。
  3. 返回命令的终止状态。

由于它关闭流然后等待命令终止,ls 有时可以尝试写入流之后它被关闭因此导致提到场景。

此外,正如 kingsindian 指出的那样,SIGPIPE 可能不会总是被提高。这是因为该命令实际上可以在主进程调用pclose() 之前完成其工作。由于这种行为是不可预测的,我建议实现一些同步。您总是想准确地了解您的程序在任何时候都处于什么状态。

附带说明,管道用于进程间通信。如果您的主进程只是打开和关闭管道,则最好使用fork()exec()

【讨论】:

  • 我同意你的解释。非常感谢!
  • +1,这并不总是会发生。这真的取决于ls 与您的程序相比有多快。您会损坏管道,因为 ls 的输出仍在管道中,但管道的写描述符不再存在。例如,如果您在关闭管道之前执行sleep(1),您将不会看到错误,因为有足够的时间来写入数据。但是,如果您真的不打算从中读取,则没有理由打开管道进行读取。
  • @kingsindian,是的,绝对的。
猜你喜欢
  • 2011-10-25
  • 1970-01-01
  • 1970-01-01
  • 2010-11-16
  • 1970-01-01
  • 2016-11-08
  • 2014-02-12
  • 2011-09-18
  • 2016-09-05
相关资源
最近更新 更多