通过 execvp 执行 sed 会导致其他管道被阻塞

问题描述 投票:0回答:1
我正在尝试

fork/pipe/dup/execvp

 概念,但遇到了一个小问题:

我做了一个测试 main 来执行排序并通过绑定到 STDIN 的管道手动发送一些数字,它按预期工作:当我关闭 stdin 编写器时,我可以读取排序后的数字输出。

但是,如果我也用他自己的一对管道(未连接到排序中使用的管道)以相同的方式启动 sed(或侦听 STDIN 的其他程序),那么我会从排序管道中读取一个块,即如果我只评论 sed 执行部分就消失了。

这个想法是能够从“第一个”读取并让其他人等待命令发送。

所以问题是: a) 它们是否共享相同的 STDIN,因此当 sed 启动时,它会被视为可能的写入者,这就是读取块的原因? 和 b) 那么我如何才能从同一个父进程

生成这 N 个进程,使它们的 STDIN 彼此不依赖? 这是测试代码:

#include <iostream> #include <unistd.h> #include <wait.h> int sed_pipe_in[2], sed_pipe_out[2], sort_pipe_in[2], sort_pipe_out[2]; pid_t execute_sort() { pid_t sort = fork(); if (sort == 0) { close(sort_pipe_in[1]); dup2(sort_pipe_in[0], STDIN_FILENO); close(sort_pipe_in[0]); close(sort_pipe_out[0]); dup2(sort_pipe_out[1], STDOUT_FILENO); close(sort_pipe_out[1]); char* args[] = { "sort", "-", NULL }; execvp("/usr/bin/sort", args); std::cerr << "Execvp failed!" << std::endl; exit(-1); } else if (sort == -1) { std::cerr << "Fork failed!" << std::endl; exit(-1); } else { close(sort_pipe_in[0]); close(sort_pipe_out[1]); } return sort; } pid_t execute_sed() { pid_t sed = fork(); if (sed == 0) { close(sed_pipe_in[1]); dup2(sed_pipe_in[0], STDIN_FILENO); close(sed_pipe_in[0]); close(sed_pipe_out[0]); dup2(sed_pipe_out[1], STDOUT_FILENO); close(sed_pipe_out[1]); char* args[] = { "sed", "-e", "s/3/9/", NULL }; execvp("/bin/sed", args); std::cerr << "Execvp failed!" << std::endl; exit(-1); } else if (sed == -1) { std::cerr << "Fork failed!" << std::endl; exit(-1); } else { close(sed_pipe_in[0]); close(sed_pipe_out[1]); } return sed; } int main() { pipe(sed_pipe_in); pipe(sed_pipe_out); pipe(sort_pipe_in); pipe(sort_pipe_out); pid_t sort = execute_sort(); // Why removing the following line makes the program to work // if sed is not yet connected to sort? pid_t sed = execute_sed(); // Only parent will get here // Sending input to sort write(sort_pipe_in[1], "3\n2\n1\n", 7); close(sort_pipe_in[1]); char buffer[500]; // If sed is started then this read is blocking ssize_t bytes = read(sort_pipe_out[0], buffer, 500); std::string output(buffer, bytes); std::cout << "Output is " << output << std::endl; // Sort will exit here as stdin is closed int status; waitpid(sort, &status, 0); return 0; }

如果
execute_sed

被注释掉,那么输出是正确的:

1
2
3

但是如果 
execute_sed

没有被注释,那么该进程在读取时被阻止。

    

pipe fork stdin execvp dup2
1个回答
0
投票
sort

sed
分叉,另一个分叉将保持另一个进程管道的文件描述符打开(因为分叉的子进程继承文件描述符)。
由于 

sorts

STDIN
仍然打开(并由
sed
进程持有),因此它继续等待输入。
您可以只拥有每个不需要的文件描述符,使用 

close()

创建管道(这将使它们在

pipe2(res_pipe, O_CLOEXEC)
上自动关闭),或者将
exec*
fcntl
/
F_GETFD
一起使用使用
F_SETFD
标记管道文件描述符以获得相同的结果。
    

© www.soinside.com 2019 - 2024. All rights reserved.