如何在c中管理shell的管道端点
我正在尝试制作一个支持管道的c型外壳。到目前为止,它一直工作,直到我尝试一个涉及一个大文件的命令,在这种情况下,它失败了。我认为这是因为我无法处理超过一根管道的数据量如何在c中管理shell的管道端点,c,shell,C,Shell,我正在尝试制作一个支持管道的c型外壳。到目前为止,它一直工作,直到我尝试一个涉及一个大文件的命令,在这种情况下,它失败了。我认为这是因为我无法处理超过一根管道的数据量 static int execute(Sequence* sequence) { pid_t pid; pid = fork(); if (pid == 0) { /* child process */ execvp(sequence->args[0], sequence->args);
static int execute(Sequence* sequence) {
pid_t pid;
pid = fork();
if (pid == 0) { /* child process */
execvp(sequence->args[0], sequence->args);
}
else if (pid < 0) {
perror("execute");
}
return pid;
}
int runCommands(Sequence* sequences, int seqSize) {
/* sets up pipes for all processes but the last */
for (i = 0; i < seqSize-1; i++) {
/* pipe, store fds and execute */
}
/* execute last */
/* wait for pids */
return 0;
}
我在main中使用正确的序列数组调用runCommands。在测试时,我发现当我使用类似“catlarge_file | head-10”的东西运行它时,head会终止,但cat不会
我是否没有正确关闭文件描述符?这是正常问题-您没有关闭足够多的文件描述符 如果您有一个三阶段管道,那么在开始分叉之前,在父进程中打开两个管道或四个描述符,再加上原始的标准输入和标准输出。当第一个子对象分叉时,它关闭4个管道描述符中的1个,即连接到其标准输出的管道描述符。它使其他3个打开,这是一场灾难。第二个子项关闭4个管道描述符中的2个,但保留其他2个打开。第三个子项关闭4个管道描述符中的1个。而且,父进程仍然打开所有文件描述符;在进行任何等待之前,它还需要关闭所有管道描述符 由于第一个管道的写入端在最后一个进程中仍然打开,第二个进程在其标准输入上没有获得EOF,因此代码挂起,第二个进程等待永远不会到达的输入 即使是在一个简单的两阶段管道中,您也会遇到这样的问题:父进程打开了管道的写入端。(我认为第二个子级也打开了管道的写入端,但父级足以挂起代码。) 你必须关闭更多的文件描述符 您可以查看和,以了解经验法则的两个小变化:
- 经验法则:如果将管道的一端复制到流程的标准输入或标准输出,则需要在该流程中关闭管道的两端
在SO上搜索“user:15168[c]rule thumb pipe”会找到10个其他答案,其中这条信息是作为经验法则呈现的。当然,你需要知道这是一个很好的搜索;你不会知道那是先验的。…还是*?我们必须至少每周以某种形式问一次这个问题。你是否尝试过搜索以前的实例(及其答案)?@Charles Duffy是的,我尝试过。其中一个是我的,你评论过了,但我被一位同行告知这不是一个足够好的问题,所以我删除了它。希望这个改写的更好。谢谢你的回复。因此,如果我理解您的意思,每次我分叉时,在我的孩子中,我应该在执行之前关闭所有文件描述符?每个孩子都应该关闭所有管道文件描述符(根据需要复制到标准输入和/或标准输出后)。父级还需要关闭所有管道文件描述符。另外,如果您很勇敢的话,POSIX规范说明,如果您尝试将文件描述符N复制到自身,那么不会出现任何问题,因此您可以简单地进行复制,而无需测试标准输入和标准输出。这是否真的是一个好主意更值得商榷,但即使是POSIX1990也需要它。
typedef struct
{
int read;
int write;
char* arg[MAX_ARGS+1];
} Sequence;