2010-10-11 68 views
3

我有一个非常简单的c/c + +程序,分支子进程执行另一个程序,然后发送一些数据到该子程序,并等待回应。(c/C++)试图强制EOF从父进程发送输入到子进程

子程序从标准输入读取并在继续之前等待EOF。

我的问题是,子程序收到来自管道写入的初始输入,但它从来没有看到EOF(即使我关闭了管道),所以它永远等待。

我不知道为什么关闭管道并不意味着孩子的stdin的EOF?

下面的代码:

http://gist.github.com/621210

+0

我我的答案更新。当我想到这个问题时,是否应该有“家庭作业”标签?这看起来很基本。 – 2010-10-11 22:12:40

+0

我向你保证这与家庭作业无关。我已经失学多年了。我不是一个c/C++编码器,但是我正在为我正在做的演示构建一个概念验证系统,并且我已经回到代码中,我没有写过10年以上的代码。 – 2010-10-11 22:16:07

回答

5

最常见的原因是你没有关闭管道的写入端,所以EOF永远不会被发送。常见的例子是,当你有一些代码看起来像:

int fds[2]; 
pipe(fds); // open a pipe 
if (fork()) { 
    // parent process 
    write(fds[1], ... // write data 
    close(fds[1]); // close it 
} else { 
    // child process 
    while (read(fds[0], ....) > 0) { 
     // read until EOF 

这里的问题是,管道的写端永远不会被关闭 - 父进程关闭它,但孩子仍然有开放写入描述符。所以孩子从不在读描述符上看到EOF。

分叉子后,你需要做的第一件事是close(fds[1]);,关闭它的写描述符的副本。这样,当父节点关闭了管道写入结束的最后一个引用时,孩子将在读取结束时看到EOF。

编辑

看着你添加的链接,这恰恰是问题 - 孩子还是有管道上的标准输出打开写端。不要将写入结尾复制到孩子的标准输出中,关闭它。发送标准输出别的地方(一个日志文件或/ dev/null的)

编辑

用于双向通信drectional,你需要两个管道:

int tochild[2], fromchild[2]; 
pipe(tochild); pipe(fromchild); 
if (fork()) { 
    close(tochild[0]); 
    close(fromchild[1]); 
    //write to tochild[1] and read from fromchild[0] 
} else { 
    dup2(tochild[0], 0); 
    dup2(fromchild[1], 1); 
    close(tochild[0]); close(tochild[1]); 
    close(fromchild[0]); close(fromchild[1]); 
    exec(... 
} 

你需要非常然而,仔细在家长中写入数据 - 如果发送给孩子的数据量很大,在阅读孩子的输出之前无法发送所有数据,否则可能会死锁(两个管道已满并且父块在孩子试图输出时试图为孩子写更多的数据)。您需要使用轮询或选择来告诉何时要读取数据或写入空间,并且您可能希望将管道(至少是父节点)置于非阻塞模式。

+0

请参阅链接代码要点中的第32-37行。我正在关闭它们。 – 2010-10-11 22:40:17

+0

第33行将它映射到标准输出,然后永远不会关闭 – 2010-10-11 22:42:27

+0

如果我需要孩子能够在完成后回复父对象,那么如何关闭孩子的实际'stdout'?我需要一个双向沟通渠道。我需要发送数据给孩子,我需要看看孩子回应什么。 – 2010-10-11 22:52:13

3

更新了什么,我觉得是这个问题: 您正在阅读到的字符和检查EOF该字符。这不是read()系统调用的工作方式。在EOF时它会返回一个0。它不会将EOF写入缓冲区。

另外我看到你一次只读一个字。这是读取数据的一种可怕的方式。它比读取大缓冲区(例如4或8kB)慢几个倍。

我相信你在这里也有一个共同的错误。你没有检查write()的返回值。

写入系统调用不保证在返回之前写入所有数据。它可能写入4000个字节并返回。它会返回写入的字节数。那么你有责任更新缓冲区指针并重新调用写入。

或者它可能会返回一个错误代码,这对你来说很重要。

+0

够公平的。这是简单的概念证明代码。在我的测试中,我发送5个字符作为输入。所以我想如果write()只发送其中的一半,我会感到惊讶。 – 2010-10-11 22:11:30

+0

此外,如果我更改孩子只准确读取5个字符(而不是等待EOF),则子程序将获得全部5个字符,并且按预期工作。所以它似乎唯一支撑是我需要孩子等待可变长度输入和EOF似乎是正确的方式来发信号。 – 2010-10-11 22:12:31

+0

你专注于问题的错误部分。我没有问题把孩子带回家。我遇到的问题是,当父母将一些数据写入到连接到孩子的stdin的管道中,然后在写入后关闭管道时,他们从未得到EOF。 – 2010-10-11 22:17:17