如何正确二次调用dup2()?管道通信子进程程序补全求助
解决管道通信中第二个子进程的标准输入重定向问题
你遇到的核心问题是没正确完成管道读端到标准输入的重定向,同时代码里还有几个细节需要调整,我来一步步帮你修正:
首先,直接替换你标记为BLANK的部分,这是第二个子进程的正确逻辑:
dup2(fd[0], STDIN_FILENO); close(fd[0]); // 重定向完成后关闭原管道读端,避免资源浪费 execl("alterna", "alterna", r2, (char *) NULL); perror("execl for alterna r2"); exit(1);
代码逻辑解释:
dup2(fd[0], STDIN_FILENO):这个调用会把管道的读端(fd[0])复制到标准输入的文件描述符(固定为0)。这样后续执行的alterna程序从标准输入读数据时,实际就是读取第一个子进程输出到管道的内容。close(fd[0]):重定向完成后,原有的fd[0]已经没有作用了,关闭它是良好的编程习惯——既避免多余的文件描述符占用资源,也能确保管道的引用计数正确,防止后续出现意外阻塞。execl调用:和第一个子进程逻辑一致,指定要执行的程序alterna,传入参数r2,最后以(char*)NULL结尾标志参数列表结束。如果execl执行失败(比如找不到alterna程序),会执行后续的错误处理代码。
额外的代码优化建议
除了BLANK部分,你的代码还有几个可以调整的细节:
main参数类型错误:原代码里int main(int argc, void *argv[])不符合C标准,应该改为int main(int argc, char *argv[]),否则会出现编译警告,甚至可能导致参数解析错误。- 父进程过早等待第一个子进程:原代码中父进程在fork第二个子进程前调用了
waitpid(pid_p, &status, 0),这会导致第一个子进程完全执行结束后才启动第二个子进程。实际上两个子进程可以并行运行:第一个子进程往管道写数据,第二个子进程从管道读数据,管道本身会自动处理阻塞(比如写满时暂停写,读空时暂停读)。建议把等待逻辑移到最后,等两个子进程都结束后再统一等待。 - 冗余的内存分配:原代码中
malloc的buffer完全没有被使用,可以直接删掉,减少不必要的内存操作。
完整修改后的代码
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <sys/wait.h> int main(int argc, char *argv[]){ if(argc != 4) { write(STDOUT_FILENO, "Inviare al programma il file di testo, r1 ed r2.\n", 49); exit(0); } int input_file; off_t file_len; // 用off_t匹配lseek的返回值类型 // 只读打开输入文件即可,无需RDWR权限 if((input_file = open(argv[1], O_RDONLY)) < 0) { perror("open"); exit(1); } if((file_len = lseek(input_file, 0, SEEK_END)) < 0) { perror("lseek"); exit(1); } if((lseek(input_file, 0, SEEK_SET)) < 0) { perror("lseek"); exit(1); } char *r1 = argv[2]; char *r2 = argv[3]; pid_t pid_p, pid_q; int status = 0; int fd[2]; if((pipe(fd)) < 0) { perror("pipe"); exit(1); } if((pid_p = fork()) < 0) { perror("fork"); exit(1); } if(pid_p == 0){ close(fd[0]); dup2(input_file, STDIN_FILENO); close(input_file); // 重定向后关闭原文件描述符 dup2(fd[1], STDOUT_FILENO); close(fd[1]); execl("alterna", "alterna", r1, (char *) NULL); perror("execl for alterna r1"); exit(1); } else{ close(fd[1]); // 父进程不需要管道写端,提前关闭 if((pid_q = fork()) < 0) { perror("fork"); exit(1); } if(pid_q == 0){ dup2(fd[0], STDIN_FILENO); close(fd[0]); execl("alterna", "alterna", r2, (char *) NULL); perror("execl for alterna r2"); exit(1); } else{ close(fd[0]); // 父进程不需要管道读端,提前关闭 // 等待两个子进程依次结束 waitpid(pid_p, &status, 0); if(!WIFEXITED(status)) { perror("p1"); exit(1); } waitpid(pid_q, &status, 0); if(!WIFEXITED(status)) { perror("p2"); exit(1); } } } return 0; }
内容的提问来源于stack exchange,提问作者FueledByPizza
相关产品推荐
相关产品推荐

