我正在用 C 语言写一个 shell,并尝试实现多个管道。我通过创建带有管道的二维数组并每次使用单独的管道来完成这个目标。管道之间的所有命令都由一个解析函数分开并放入结构体中。在每个管道之间的每条命令行都有自己的进程。对于中间的所有命令,我尝试从前一个进程读取并写入下一个进程。问题似乎就出在这里。当我尝试使用多个管道时,一个管道可以正常工作,但是当我使用多个管道时,程序没有输出并且被卡住了。在 GDB 中,在第二个进程 fork 后,我会收到 execvp 失败的消息。这可能是什么原因?
int create_pipe(int* fd)
{
int pipe_id = pipe(fd);
if (pipe_id == -1)
{
return -1;
}
return 0;
}
void write_pipe(int* fd)
{
close(fd[READ]);
if ((dup2(fd[WRITE], STDOUT_FILENO)) < -1)
{
fork_error();
}
close(fd[WRITE]);
}
void read_pipe(int *fd)
{
close(fd[WRITE]);
if (dup2(fd[READ], STDIN_FILENO) < 0)
{
fork_error();
}
close(fd[READ]);
}
void need_to_pipe (int i, int (*fd)[2])
{
if (commands[i].pos == first)
{
write_pipe(fd[i * 2]);
}
else if (commands[i].pos == last)
{
read_pipe(fd[(i-1) *2]);
}
else //if (commands[i].pos == middle)
{
dup2(fd[(i-1)*2][READ], STDIN_FILENO);
close(fd[(i-1)*2][READ]);
close(fd[(i-1)*2][WRITE]);
//close(fd[(i)*2][READ]);
//close(fd[(i)*2][WRITE]);
close(fd[(i)*2][READ]);
dup2(fd[i*2][WRITE], STDOUT_FILENO);
close(fd[(i)*2][WRITE]);
}
}
void fork_cmd(int i, int (*fd)[2]) {
pid_t pid;
switch (pid = fork()) {
case -1:
fork_error();
case 0:
if (!(commands[i].pos == single))
{
need_to_pipe(i, fd);
}
if (execvp(commands[i].argv[0], commands[i].argv)<0)
{
exit(EXIT_FAILURE);
}
}
}
void fork_cmds(int n, int (*fd)[2])
{
for (int i = 0; i < n; i++)
{
fork_cmd(i, fd);
}
}
void wait_once ()
{
wait(NULL);
}
void wait_for_all_cmds(int n)
{
for (int i = 0; i < n; i++)
{
wait_once();
//wait for number of child processes.
}
}
int main() {
int n;
size_t size = 256;
char line[size];
while(true) {
get_line(line, size);
n = parse_cmds(line, commands);
int fd[(n-1)][2];
for(int i =0;i<n-1;i++)
{
int pipe_id = pipe(fd[i*2]);
if (pipe_id == -1)
{
return -1;
}
}
fork_cmds(n, fd);
for(int i =0;i<n-1;i++)
{
int *fdclose= fd[i*2];
close (fdclose[READ]);
close (fdclose[WRITE]);
}
wait_for_all_cmds(n);
}
exit(EXIT_SUCCESS);
}
printf(" >>> ");
---> 要么添加\n
,要么刷新stdout
。否则您可能看不到提示符。 - Harisint create_pipe(int* fd) { int pipe_id = pipe(fd); if (pipe_id == -1) { return -1; } return 0; }
是一种冗长的写法,可以简化为int create_pipe(int* fd) { return pipe(fd); }
— 然后你其实不需要create_pipe()
函数了(直接调用pipe()
即可)。在create_pipe()
函数体中多出来的5行代码没有任何好处。 - Jonathan Leffler