我正在尝试在c中实现unix管道(即执行ls | wc)。我找到了一个与我的问题相关的解决方案(C Unix Pipes Example)但是,我不确定为什么解决的代码段的特定部分有效。
以下是代码:
/* Run WC. */
int filedes[2];
pipe(filedes);
/* Run LS. */
pid_t pid = fork();
if (pid == 0) {
/* Set stdout to the input side of the pipe, and run 'ls'. */
dup2(filedes[1], 1);
char *argv[] = {"ls", NULL};
execv("/bin/ls", argv);
} else {
/* Close the input side of the pipe, to prevent it staying open. */
close(filedes[1]);
}
/* Run WC. */
pid = fork();
if (pid == 0) {
dup2(filedes[0], 0);
char *argv[] = {"wc", NULL};
execv("/usr/bin/wc", argv);
}
在执行wc命令的子进程中,虽然它将stndin附加到文件描述符,但似乎我们没有在第一个子进程中显式读取ls生成的输出。因此,对我而言,似乎ls独立运行并且wc独立运行,因为我们在执行wc时没有明确地使用ls的输出。那么这段代码是如何工作的(即它执行ls | wc)?
答案 0 :(得分:3)
显示的代码工作(它会切割多个角,但它可以工作),因为分叉的子代确保执行的进程将写入的文件描述符(在ls
的情况下)和读取(在wc
的情况下)是管道的适当末端。你不必再做了什么;标准输入是文件描述符0,因此没有(文件名)参数的wc
从标准输入读取。 ls
总是写入标准输出文件描述符1,除非它正在编写错误消息。
代码段中有三个进程;父进程和两个子进程,每个fork()
一个。
父进程也应该关闭管道的两端;它只关闭一个。
通常,在对管道文件描述符执行dup()
或dup2()
调用后,应关闭管道的两端。你在这里得到它,因为ls
生成数据并终止;在任何情况下你都不会。
评论:
/* Set stdout to the input side of the pipe, and run 'ls'. */
不准确;您将stdout
设置为管道的输出侧,而不是输入侧。
execv()
来电后你应该有一个错误退出;如果他们失败了,他们就会回来,而且这个过程会造成严重破坏(例如,如果ls
失败,你最终会得到两份wc
正在运行的副本。
请注意在每个过程中仔细关闭管道的两端。一旦启动了两个子进程,父进程就无法使用该进程。我保留了早期关闭filedes[1]
的代码(但是将其从显式else
块中删除了,因为以下代码也仅在else
执行时执行)。我可能会在需要关闭文件的三个代码路径中的每一个中保留closes()
对。
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void)
{
int filedes[2];
int corpse;
int status;
pipe(filedes);
/* Run LS. */
pid_t pid = fork();
if (pid == 0)
{
/* Set stdout to the output side of the pipe, and run 'ls'. */
dup2(filedes[1], 1);
close(filedes[1]);
close(filedes[0]);
char *argv[] = {"ls", NULL};
execv("/bin/ls", argv);
fprintf(stderr, "Failed to execute /bin/ls\n");
exit(1);
}
/* Close the input side of the pipe, to prevent it staying open. */
close(filedes[1]);
/* Run WC. */
pid = fork();
if (pid == 0)
{
/* Set stdin to the input side of the pipe, and run 'wc'. */
dup2(filedes[0], 0);
close(filedes[0]);
char *argv[] = {"wc", NULL};
execv("/usr/bin/wc", argv);
fprintf(stderr, "Failed to execute /usr/bin/wc\n");
exit(1);
}
close(filedes[0]);
while ((corpse = waitpid(-1, &status, 0)) > 0)
printf("PID %d died 0x%.4X\n", corpse, status);
return(0);
}
示例输出:
$ ./pipes-14312939
32 32 389
PID 75954 died 0x0000
PID 75955 died 0x0000
$