2016-02-27 49 views
0

我有一些C代码叫做c-shell,它执行以下操作。父c-shell在Linux命令行中读取,并分叉子进程以执行该命令。孩子不会执行命令,直到它收到来自父母的信号,表示它已准备好执行命令。它可以处理用于给命令参数的输入文件,或者它可以从命令行读取它们。它可以处理发送输出到输出文件,而不仅仅是将执行的命令输出打印到标准输出。它将输出发送到输出文件的方式是由孩子将其stdout重定向到一个管道,并且一旦它接收到子进程完成运行的sig-child信号,父进程就从该管道读取数据。它可以处理多个命令(在命令之间放置分号的地方)。它可以将第一个命令的管道输出处理为命令行中的第二个命令。然而 - 这是我的问题 - 它不能处理一个命令,你将一个命令的输出作为第二个命令的输入,然后将第二个命令的输出发送到输出文件。我感到困惑,因为所有上述情况都很好。我可以将输出从执行的子进程重定向到父进程完成后,以便它可以完成它。我可以将运行的第一个命令的输出重定向为第二个运行命令的输入。但是如果我尝试将输出发送到第二个命令到输出文件,我不能这样做。如果这个问题没有意义,我会发表更多细节。Linux操作系统 - 父,子,父进程的输入输出管道

例如:如果我进入我的c-shell下面的命令行:ls -l | grep lsOut(意思是,我做了一个详细的目录列表,并且在该目录列表输出中,有一些文件包含字符“lsOut”(来自ls命令的输出文件),并且grep命令应该过滤掉所有其他文件在不包含这些字符的目录列表中,当它打印到标准输出时工作得很好,当我执行如下命令时:ps> psOut,ps命令的输出写入psOut文件没有问题,但是,如果我执行以下命令:ls -l | grep lsOut> lsOutFile,会发生什么令人困惑的事情,它将第一个命令ls -l输出到stdout,虽然我在打印语句中看到第二个命令grep lsOut正在运行,并且应该接收来自ls -l的输出作为grep lsOut的输入,它似乎没有任何影响。唯一的输出是整个ls -l目录,没有grep过滤,尽管它说它将它写入输出文件,它不会到达那里,如果你想让我发布一个代码链接,我可以做到这一点非常感谢!我花了数小时试图调试这个问题。

+0

墙上的文字,难以阅读,与您的实际问题在中间的某个地方。您可能需要使用更多段落。 – Evert

+0

有没有订单问题:'ls -l | grep lsOut> lsOutFile'评估为'ls -l | (grep lsOut> lsOutFile)'而不是'(ls -l | grep lsOut)> lsOutFile'? (括号可能只是为了排序,而不是为了任何其他含义。) – Evert

+0

不解析'ls' http://mywiki.wooledge.org/ParsingLs – jkdba

回答

0

它发送输出到输出文件的方式是通过孩子 重定向它的标准输出到管道,一旦接收到SIG-孩子信号子进程结束父从这个管道 读 正在运行。

把它放在这里。俗话说:不要通过“去”。不要收200美元。

这部分已经不太正确了。如果子进程开始喷出足够的输出量,那么在这里最终会同时存在一个挂起的父进程和一个挂起的子进程。

管道缓冲区的大小并不是无限的。管道缓冲区具有固定的最大内部大小。我的回忆是默认的管道缓冲区大小是8,192字节。它实际上可能是其他的东西,但实际大小并不重要。无论管道缓冲区大小是什么,一旦缓冲区填满,写入管道缓冲区的进程就会进入休眠状态,直到读取过程开始通过读取管道清空管道。只要读者和作家独立工作,一个人的阅读,一个人的写作,一切顺利。如果作者的写作速度超过读者阅读的速度,一旦未读字符数达到管道的最大大小,内核就悄悄地将作者进程休眠到write()之内,直到读者赶上。

如果您的父进程等待子进程在从标准输出管道开始读取之前等待子进程退出,并且子进程写入多于8,192字节(或实际大小的任何字节)字节,则子进程将在其内部暂停打电话给write(),直到管道读取。由于父进程不会从管道读取,直到子进程终止,两个进程将永远等待对方。

所以,我们已经知道你的应用程序没有正确处理这种情况。尽管您已经描述了与应用程序稍有不同的问题,但鉴于应用程序没有正确处理进程间管道语义,很可能您的实际问题(如果不是这样)密切相关。

您必须彻底重新设计您的应用程序如何正确实施工艺管道间。

+0

我不知道我可能超过了8192字节的管道缓冲区限制。我不认为我的整个应用程序是不正确的,但现在我可以看到,如果我将数据发送到父级以发送到outfile,这是一个问题。我发现了另一个解决方案,我会在星期一尝试,那就是我直到今天我还没有听说过的tee()命令。我认为它会将管道中的内容发送到outfile。这可能有帮助。感谢您的回应!我还没有上过这堂课。只是自己学习,不是CS专业,但在这里和那里有几个CS课程。 ;-) – user1943660

+0

在父类中,我没有在查找子输出之前等待sig-child,而是使用select()来监视管道描述符,然后使用ioctl和splice()将输出发送到输出文件,直到孩子跑完了,这似乎工作。我仍然遇到麻烦。如果来自第一个子命令的输出很大,并且您将其重定向为下一个子命令的输入,那么您可以使用setbuf()来放大管道的缓冲区吗?如果我在第一个命令中执行dir列表,并且尝试在下一个命令中查找某个模式,我遇到了麻烦。 – user1943660

+0

setbuf()会影响进程FILE的缓冲区大小。它对内部Linux内核管道缓冲区没有影响。而且,管道缓冲区的大小对正确实现的管道应该没有影响。即使内部管道缓冲区只有一个字节长,只要管道设置正确,将一个程序的标准输出管道连接到另一个程序的标准输入也能保证正常工作。 –

相关问题