ubuntu 为什么我的C程序的管道有两个管道挂起?

cngwdvgl  于 2024-01-06  发布在  其他
关注(0)|答案(3)|浏览(343)

我正在尝试写一个C程序,它可以执行类似于管道ls | wc | wc的操作。我已经为ls | wc执行过了,它运行得很好,但我不知道为什么我的程序会停在指定行的子进程上。

  1. int main (void)
  2. {
  3. pid_t pid_fils, pid_pfils;
  4. int fd[2], fd2[2];
  5. if(pipe(fd)==-1 || pipe(fd2)==-1)
  6. {
  7. printf("pipe failed!");
  8. return 1;
  9. }
  10. printf("program started\n");
  11. pid_fils=fork();
  12. if(pid_fils==0)
  13. {
  14. pid_pfils=fork();
  15. if(pid_pfils==0)
  16. {
  17. //action3
  18. printf("I am the grandson\n");
  19. close(fd[0]);//close read side
  20. dup2(fd[1],1);//connect write with stdout
  21. close(fd[1]);//close write side
  22. execlp("ls","ls",(char*)0);
  23. //execvp("ls",argv3);
  24. return 0;/*actions grandson*/
  25. }
  26. else
  27. {
  28. //action2
  29. printf("I am the son\n");
  30. wait();
  31. printf("son, wait ok\n");
  32. >close(fd[1]); //close read side
  33. >dup2(fd[0],0); //connect write with stdin
  34. >close(fd[0]); //close read side
  35. ///////pipe2////
  36. > close(fd2[0]); //close read side
  37. >dup2(fd2[1],1); //connect write with stdout/*it stops here -can't display "ok!"*/
  38. printf("ok!\n");
  39. >close(fd2[1]); //close write side
  40. execlp("wc","wc",(char*)0);
  41. printf("error exec returned!\n");
  42. return 0;
  43. }
  44. }
  45. else
  46. {
  47. ///action1
  48. printf("I am the parent\n");
  49. wait();
  50. printf("parent,wait ok\n");
  51. close(fd2[1]); //close write side,
  52. dup2(fd2[0],0); //connect read with stdin
  53. close(fd2[0]); //close read side
  54. execlp("wc","wc",(char*)0);
  55. return 0;/*the parent*/
  56. }
  57. return 1;
  58. }

字符串

uhry853o

uhry853o1#

确保关闭所有未使用的描述符。在您的情况下,最简单的解决方案是将管道(fd)的创建移动到第一个if块(在第一个子进程中)。问题是,只要任何进程都可能写入管道,读取器就不会被删除,因此不会终止。

  1. if(pipe(fd2)==-1)
  2. {
  3. printf("pipe failed!");
  4. return 1;
  5. }
  6. printf("program started\n");
  7. pid_fils=fork();
  8. if(pid_fils==0)
  9. {
  10. if(pipe(fd)==-1)
  11. {
  12. printf("pipe failed!");
  13. return 1;
  14. }
  15. pid_pfils=fork();

字符串
我还应该提一下,你可能需要重新考虑等待调用。不确定你打算用它们做什么,但你不希望“ls”进程在输出时阻塞,因为阅读器还没有启动。

展开查看全部
wbrvyc0a

wbrvyc0a2#

  1. dup2(fd2[1],1);

字符串
上面一行将首先关闭描述符1处的文件,然后将描述符从fd2[1]复制到1。
1是stdout。意味着调用关闭了stdout。
printf打印到stdout,这意味着printf打印到1,它现在被分配给管道fd2
所以你的OK进入了管道而不是在屏幕上。
尝试

  1. //action2
  2. printf("I am the son\n");
  3. wait();
  4. printf("son, wait ok\n");
  5. close(fd[1]); //close read side
  6. dup2(fd[0],0); //connect write with stdin
  7. close(fd[0]); //close read side
  8. ///////pipe2////
  9. int my_terminal_out = dup(1);
  10. close(fd2[0]); //close read side
  11. dup2(fd2[1],1); //connect write with stdout/*it stops here -can't display "ok!"*/
  12. fprintf(my_terminal_out, "ok!\n");
  13. close(fd2[1]); //close write side


还没有测试。你应该测试你的代码的其余部分是否有类似的错误。
”DrC说。

展开查看全部
mf98qq94

mf98qq943#

扩展这个SO answer,我们可以创建一个额外的管道,fork另一个进程,并相应地连接管道。

  1. // two-pipes.c
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. #include <sys/wait.h>
  6. // C implementation for the `ls -la | wc | wc` pipeline.
  7. int main(int argc, char *argv[]) {
  8. // We declare two pipes, one for each pair of processes, i.e.,
  9. // ls -al pipefd1 wc pipefd2 wc
  10. int pipefd1[2];
  11. int pipefd2[2];
  12. pid_t ls_pid, wc_pid1, wc_pid2;
  13. pipe(pipefd1);
  14. pipe(pipefd2);
  15. // CHILD PROCESS: ls
  16. if ((ls_pid = fork()) == 0) {
  17. // We close-and-then-connect STDOUT to pipefd1's write end so the
  18. // process write to the pipe instead of the screen.
  19. dup2(pipefd1[1], STDOUT_FILENO);
  20. // Since STDOUT_FILENO also refers to pipefd's write end, we can
  21. // close this file descriptor; it's no longer needed.
  22. close(pipefd1[1]);
  23. // The process doesn't use these file descriptors so we close them.
  24. close(pipefd1[0]);
  25. close(pipefd2[0]);
  26. close(pipefd2[1]);
  27. // Execute the `ls` command, and exit if errors out.
  28. if ((execl("/bin/ls", "ls", "-al", (char *) NULL)) < 0) exit(0);
  29. }
  30. else if (ls_pid < 0) {
  31. fprintf(stderr, "failed to fork ls process");
  32. exit(0);
  33. }
  34. // CHILD PROCESS: wc (1)
  35. if ((wc_pid1 = fork()) == 0) {
  36. // We close-and-then-connect STDIN and STDOUT to pipefd1's read and
  37. // and pipefd2's write end so the process read from pipefd1 and write
  38. // to pipefd2 instead of from the keyboard and to the screen respectively.
  39. dup2(pipefd1[0], STDIN_FILENO);
  40. dup2(pipefd2[1], STDOUT_FILENO);
  41. // Since STDIN_FILENO and STDOUT_FILENO also refer to pipefd1's read
  42. // end and pipefd2's write end respectively, we can close these file
  43. // descriptors.
  44. close(pipefd1[0]);
  45. close(pipefd2[1]);
  46. // The process doesn't use these file descriptors so we close them.
  47. close(pipefd1[1]);
  48. close(pipefd2[0]);
  49. // Execute the `wc` command, and exit if errors out.
  50. if ((execl("/usr/bin/wc", "wc", (char *) NULL)) < 0) exit(0);
  51. }
  52. else if (wc_pid1 < 0) {
  53. fprintf(stderr, "failed to fork wc process");
  54. exit(0);
  55. }
  56. // CHILD PROCESS: wc (2)
  57. if ((wc_pid2 = fork()) == 0) {
  58. // We close-and-then-connect STDIN to pipefd2's read end so the process
  59. // read from the pipe instead of from the keyboard.
  60. dup2(pipefd2[0], STDIN_FILENO);
  61. // Since STDIN_FILENO also refers to the pipefd2's read end, we can
  62. // close this file descriptor; it's no longer needed.
  63. close(pipefd2[0]);
  64. // The process doesn't use these file descriptors so we close them.
  65. close(pipefd1[0]);
  66. close(pipefd1[1]);
  67. close(pipefd2[1]);
  68. // Execute the `wc` command, and exit if errors out.
  69. if ((execl("/usr/bin/wc", "wc", (char *) NULL)) < 0) exit(0);
  70. }
  71. else if (wc_pid1 < 0) {
  72. fprintf(stderr, "failed to fork wc process");
  73. exit(0);
  74. }
  75. // PARENT PROCESS
  76. // The parent process isn't using the pipes, however these descriptors are
  77. // another references to the pipe's read and write ends and we must close
  78. // them. Otherwise, it doesn't send the EOF so the children can continue
  79. // (children block until all input has been processed).
  80. close(pipefd1[0]);
  81. close(pipefd1[1]);
  82. close(pipefd2[0]);
  83. close(pipefd2[1]);
  84. // The parent process waits for the three child processes to finish before
  85. // exiting.
  86. int ls_status, wc_status1, wc_status2;
  87. pid_t ls_wpid = waitpid(ls_pid, &ls_status, 0);
  88. pid_t wc_wpid1 = waitpid(wc_pid1, &wc_status1, 0);
  89. pid_t wc_wpid2 = waitpid(wc_pid2, &wc_status2, 0);
  90. // Return main's status based on whether the parent process waited both
  91. // child processes successfully. Status based only on `ls_status`.
  92. return
  93. ls_pid == ls_wpid && WIFEXITED(ls_status) &&
  94. wc_pid1 == wc_wpid1 && WIFEXITED(wc_status1) &&
  95. wc_pid2 == wc_wpid2 && WIFEXITED(wc_status2)
  96. ? WEXITSTATUS(ls_status)
  97. : -1;
  98. }

字符串
编译并运行它:

  1. $ ls -la
  2. total 112
  3. drwxr-xr-x 8 256 Nov 20 13:52 .
  4. drwxr-x---+ 91 2912 Nov 20 13:55 ..
  5. -rwxr-xr-x 1 33896 Nov 20 13:48 a.out
  6. -rw-r--r-- 1 45 Nov 17 15:33 error.log
  7. -rw-r--r--@ 1 2390 Nov 20 09:51 ls-wc-pipes.c
  8. -rw-r--r-- 1 116 Nov 17 16:01 out.log
  9. -rw-r--r--@ 1 2647 Nov 20 09:49 so-pipes.c
  10. -rw-r--r--@ 1 4021 Nov 20 13:52 two-pipes.c
  11. $ gcc two-pipes.c && ./a.out
  12. 1 3 25

展开查看全部

相关问题