我一直在尝试使用pipe()系统调用来创建一个支持管道的shell(使用任意数量的命令)。
不幸的是,我使用pipe()并没有太多运气。在花了几天时间查看各种在线资源之后,我决定整理一个过度简化的程序,该程序与执行ls | sort
具有相同的效果,看看我是否能够为两个兄弟,子进程工作。这是代码:
#include <sys/wait.h>
#include <unistd.h>
void run(char *cmd) {
char *args[2];
args[0] = cmd;
args[1] = NULL;
execvp(cmd, args);
}
int main(void) {
int filedes[2];
pipe(filedes);
pid_t pid_a, pid_b;
if (!(pid_a = fork())) {
dup2(filedes[1], 1);
run("ls");
}
if (!(pid_b = fork())) {
dup2(filedes[0], 0);
run("sort");
}
waitpid(pid_a, NULL, 0);
waitpid(pid_b, NULL, 0);
return 0;
}
在父级中创建管道,我知道在execvp()调用之后,每个子进程都继承了pipe()在父级中创建的文件描述符。对于ls
进程,我使用dup2()将其标准输出(1)重定向到管道的写入端,对于sort
进程,重定向(0)中的标准到管道的读端。
最后,我等待两个进程完成后再退出。
我的直觉告诉我这应该有效,但事实并非如此!
有什么建议吗?
答案 0 :(得分:6)
您必须关闭不使用的管道。
至少sort
将从stdin读取,直到stdin关闭。
在这种情况下,它的stdin永远不会关闭,因为你仍然有2个打开的文件描述符。
将您的计划更改为
if (!(pid_a = fork())) {
dup2(filedes[1], 1);
closepipes(filedes);
run("ls");
}
if (!(pid_b = fork())) {
dup2(filedes[0], 0);
closepipes(filedes);
run("sort");
}
closepipe(filedes);
waitpid(pid_a, NULL, 0);
waitpid(pid_b, NULL, 0);
其中closepipes就像
void closepipes(int *fds)
{
close(fds[0]);
close(fds[1]);
}
答案 1 :(得分:4)
在父进程中调用waitpid
之前,必须从管道中关闭所有不需要的文件描述符。这些是:
filedes[0]
中pid_a
在filedes[1]
pid_b
filedes[0]
和filedes[1]
您还应检查pipe()
和fork()
是否未返回-1
,这意味着发生了错误。
答案 2 :(得分:3)
您需要关闭(至少)父进程中管道的写入端。否则,管道的读取端将永远不会读取EOF状态,sort
将永远不会完成。
答案 3 :(得分:1)
此代码正常运行...
#include <sys/wait.h>
#include <unistd.h>
using namespace std;
void run(char *cmd) {
char *args[2];
args[0] = cmd;
args[1] = NULL;
execvp(cmd, args);
}
void closepipe(int *fds)
{
close(fds[0]);
close(fds[1]);
}
int main(int argc,char *argv[]) {
int filedes[2];
pipe(filedes);
char lss[]="ls";
char sorts[]="sort";
pid_t pid_a, pid_b;
chdir(argv[1]);
if (!(pid_a = fork())) {
dup2(filedes[1], 1);
closepipe(filedes);
run(lss);
}
if (!(pid_b = fork())) {
dup2(filedes[0], 0);
closepipe(filedes);
run(sorts);
}
closepipe(filedes);
waitpid(pid_a, NULL, 0);
waitpid(pid_b, NULL, 0);
return 0;
}