执行 ls | c 程序中的 wc linux 命令使用 2 个进程通过管道进行通信
Executing the ls | wc linux command in c program using 2 processes communicating trough a pipe
我目前在进行以下练习时遇到问题:
我想用以下程序“模仿”linux bash 中的管道命令行 ls | wc
。
我做的是:
- 创建管道
- 创建 reader child 和作家 child
- 作者child关闭管道的读取端并将其标准输出重定向到管道的写入端
- reader child 关闭管道的写入端并使管道的读取端成为他的标准输入
- both children do an exec, writer 执行
ls
程序,通过管道将输出传递给执行 wc
程序的 reader那个输出。
当我在 linux 终端中执行 ls | wc
时,我得到以下结果:
8 8 101
但是如果我执行我的程序,我会得到以下结果:
0 0 0
这是我的程序:
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>
#include <libgen.h>
#include <signal.h>
#include <errno.h>
int main(void){
int mypipe[2];
pid_t pid1, pid2;
if (pipe(mypipe)<0)
perror ("pipe error"), exit(1);
if ((pid1=fork())<0)
perror ("fork error"), exit(1);
else if (pid1==0) {
//reader child
close (mypipe[1]);
if (dup2(mypipe[0], STDIN_FILENO)!=STDIN_FILENO)
perror ("dup2 error"), exit(1);
close (mypipe[0]);
if (execlp("wc", "wc", NULL)<0)
perror("execlp1 error"), exit(1);
else { //pid >0, parent
if ((pid2=fork())<0)
perror ("fork error"), exit(2);
else if (pid2==0) {
//writer child
close(mypipe[0]);
if (dup2(mypipe[1], STDOUT_FILENO) != STDOUT_FILENO)
perror("dup2 error"), exit(1);
close (mypipe[1]);
if (execlp("ls", "ls", NULL)<0)
perror ("execlp error"), exit(1);
}
else { //parent
close(mypipe[0]);
close(mypipe[1]);
waitpid(pid1, NULL, 0);
waitpid(pid2, NULL, 0);
exit(0);
}
}
}
return 0;
}
我做错了什么?预先感谢您的回答!
您的代码很混乱。你有很多不相关的headers,重复#include <errno.h>
。在 main()
函数中,您有:
int main(void)
{
int mypipe[2];
pid_t pid1, pid2;
if (pipe(mypipe) < 0)
perror("pipe error"), exit(1);
if ((pid1 = fork()) < 0)
perror("fork error"), exit(1);
else if (pid1 == 0)
{
// reader child
close(mypipe[1]);
if (dup2(mypipe[0], STDIN_FILENO) != STDIN_FILENO)
perror("dup2 error"), exit(1);
close(mypipe[0]);
if (execlp("wc", "wc", NULL) < 0)
perror("execlp1 error"), exit(1);
else // pid >0, parent
{
…
}
}
return 0;
}
else if (pid1 == 0)
子句由child 执行。它关闭管道的写入端,将读取端复制到标准输入并关闭管道的读取端。然后它在 wc
上执行 execlp()
。只有代码执行失败 wc
才会执行 else
子句,然后只有管道的读取端保持打开状态。同时,原来的进程简单地退出。这将关闭管道,因此 wc
命令没有输入,结果报告 0 0 0
。
您需要重写代码。 parent 进程应该等到它的 children 都执行。尤其是在调试的时候,不要忽视children的退出状态,应该报出来。
这是一些有效的代码。请注意,它避免了繁琐的决策树——它是 if
/ else if
/ … / else
代码的线性序列。一般来说,这比繁琐的 multi-level 条件集更容易理解。
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void)
{
int fd[2];
pid_t pid1, pid2;
if (pipe(fd) < 0)
perror("pipe error"), exit(1);
else if ((pid1 = fork()) < 0)
perror("fork error"), exit(1);
else if (pid1 == 0)
{
/* ls */
dup2(fd[1], STDOUT_FILENO);
close(fd[0]);
close(fd[1]);
execlp("ls", "ls", (char *)0);
perror("exec ls");
exit(1);
}
else if ((pid2 = fork()) < 0)
perror("fork error"), exit(1);
else if (pid2 == 0)
{
/* wc */
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
close(fd[1]);
execlp("wc", "wc", (char *)0);
perror("exec wc");
exit(1);
}
else
{
close(fd[0]);
close(fd[1]);
int status1;
int status2;
int corpse1 = waitpid(pid1, &status1, 0);
int corpse2 = waitpid(pid2, &status2, 0);
printf("ls: pid = %d, corpse = %d, exit status = 0x%.4X\n", pid1, corpse1, status1);
printf("ls: pid = %d, corpse = %d, exit status = 0x%.4X\n", pid2, corpse2, status2);
}
return 0;
}
在我的机器上生成的程序 pipe41
的示例 运行:
$ pipe41
175 175 1954
ls: pid = 44770, corpse = 44770, exit status = 0x0000
ls: pid = 44771, corpse = 44771, exit status = 0x0000
$ ls | wc
175 175 1954
$
我目前在进行以下练习时遇到问题:
我想用以下程序“模仿”linux bash 中的管道命令行 ls | wc
。
我做的是:
- 创建管道
- 创建 reader child 和作家 child
- 作者child关闭管道的读取端并将其标准输出重定向到管道的写入端
- reader child 关闭管道的写入端并使管道的读取端成为他的标准输入
- both children do an exec, writer 执行
ls
程序,通过管道将输出传递给执行wc
程序的 reader那个输出。
当我在 linux 终端中执行 ls | wc
时,我得到以下结果:
8 8 101
但是如果我执行我的程序,我会得到以下结果:
0 0 0
这是我的程序:
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>
#include <libgen.h>
#include <signal.h>
#include <errno.h>
int main(void){
int mypipe[2];
pid_t pid1, pid2;
if (pipe(mypipe)<0)
perror ("pipe error"), exit(1);
if ((pid1=fork())<0)
perror ("fork error"), exit(1);
else if (pid1==0) {
//reader child
close (mypipe[1]);
if (dup2(mypipe[0], STDIN_FILENO)!=STDIN_FILENO)
perror ("dup2 error"), exit(1);
close (mypipe[0]);
if (execlp("wc", "wc", NULL)<0)
perror("execlp1 error"), exit(1);
else { //pid >0, parent
if ((pid2=fork())<0)
perror ("fork error"), exit(2);
else if (pid2==0) {
//writer child
close(mypipe[0]);
if (dup2(mypipe[1], STDOUT_FILENO) != STDOUT_FILENO)
perror("dup2 error"), exit(1);
close (mypipe[1]);
if (execlp("ls", "ls", NULL)<0)
perror ("execlp error"), exit(1);
}
else { //parent
close(mypipe[0]);
close(mypipe[1]);
waitpid(pid1, NULL, 0);
waitpid(pid2, NULL, 0);
exit(0);
}
}
}
return 0;
}
我做错了什么?预先感谢您的回答!
您的代码很混乱。你有很多不相关的headers,重复#include <errno.h>
。在 main()
函数中,您有:
int main(void)
{
int mypipe[2];
pid_t pid1, pid2;
if (pipe(mypipe) < 0)
perror("pipe error"), exit(1);
if ((pid1 = fork()) < 0)
perror("fork error"), exit(1);
else if (pid1 == 0)
{
// reader child
close(mypipe[1]);
if (dup2(mypipe[0], STDIN_FILENO) != STDIN_FILENO)
perror("dup2 error"), exit(1);
close(mypipe[0]);
if (execlp("wc", "wc", NULL) < 0)
perror("execlp1 error"), exit(1);
else // pid >0, parent
{
…
}
}
return 0;
}
else if (pid1 == 0)
子句由child 执行。它关闭管道的写入端,将读取端复制到标准输入并关闭管道的读取端。然后它在 wc
上执行 execlp()
。只有代码执行失败 wc
才会执行 else
子句,然后只有管道的读取端保持打开状态。同时,原来的进程简单地退出。这将关闭管道,因此 wc
命令没有输入,结果报告 0 0 0
。
您需要重写代码。 parent 进程应该等到它的 children 都执行。尤其是在调试的时候,不要忽视children的退出状态,应该报出来。
这是一些有效的代码。请注意,它避免了繁琐的决策树——它是 if
/ else if
/ … / else
代码的线性序列。一般来说,这比繁琐的 multi-level 条件集更容易理解。
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void)
{
int fd[2];
pid_t pid1, pid2;
if (pipe(fd) < 0)
perror("pipe error"), exit(1);
else if ((pid1 = fork()) < 0)
perror("fork error"), exit(1);
else if (pid1 == 0)
{
/* ls */
dup2(fd[1], STDOUT_FILENO);
close(fd[0]);
close(fd[1]);
execlp("ls", "ls", (char *)0);
perror("exec ls");
exit(1);
}
else if ((pid2 = fork()) < 0)
perror("fork error"), exit(1);
else if (pid2 == 0)
{
/* wc */
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
close(fd[1]);
execlp("wc", "wc", (char *)0);
perror("exec wc");
exit(1);
}
else
{
close(fd[0]);
close(fd[1]);
int status1;
int status2;
int corpse1 = waitpid(pid1, &status1, 0);
int corpse2 = waitpid(pid2, &status2, 0);
printf("ls: pid = %d, corpse = %d, exit status = 0x%.4X\n", pid1, corpse1, status1);
printf("ls: pid = %d, corpse = %d, exit status = 0x%.4X\n", pid2, corpse2, status2);
}
return 0;
}
在我的机器上生成的程序 pipe41
的示例 运行:
$ pipe41
175 175 1954
ls: pid = 44770, corpse = 44770, exit status = 0x0000
ls: pid = 44771, corpse = 44771, exit status = 0x0000
$ ls | wc
175 175 1954
$