在Unix C中使用管道
我在使用C管道时遇到了很大的麻烦.我应该从命令行接受参数(例如:./myprogram 123 45 67),一次将一个字符的参数读入缓冲区,将字符发送到要计算的子进程,然后返回读取到父进程的字符总数.我的代码如下(注意:评论是我应该做的):
// Characters from command line arguments are sent to child process // from parent process one at a time through pipe. // Child process counts number of characters sent through pipe. // Child process returns number of characters counted to parent process. // Parent process prints number of characters counted by child process. #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <signal.h> static int toChild[2]; static int fromChild[2]; static char buffer; int main(int argc,char **argv) { int status; int nChars = 0; pid_t pid; pipe(toChild); pipe(fromChild); if ((pid = fork()) == -1) { printf("fork error %dn",pid); return -1; } else if (pid == 0) { close(toChild[1]); close(fromChild[0]); // Receive characters from parent process via pipe // one at a time,and count them. int count = 0; printf("child about to readn"); while(read(toChild[0],&buffer,1)){ count++; } // Return number of characters counted to parent process. write(fromChild[1],&count,sizeof(count)); close(toChild[0]); close(fromChild[1]); printf("child exitsn"); } else { close(toChild[0]); close(fromChild[1]); // -- running in parent process -- printf("CS201 - Assignment 3 - Chris Gavetten"); write(toChild[1],&argv[1],1); // Send characters from command line arguments starting with // argv[1] one at a time through pipe to child process. read(fromChild[0],&nChars,1); // Wait for child process to return. Reap child process. // Receive number of characters counted via the value // returned when the child process is reaped. close(toChild[1]); close(fromChild[0]); waitpid(pid,&status,0); printf("child counted %d charsn",nChars); printf("parent exitsn"); return 0; } } 即使我关闭了两个管道的两端,子进程似乎仍然挂起. 解决方法
对于初学者来说,这是错误的.
write(toChild[1],1) 它最终将导致您的问题. count是一个int,而不是char或unsigned char.你需要发送sizeof(count).此外,按下错误时的读取功能将返回EOF,这是非零,因此您的子退出条件不合适.它应该看起来像这样: while(read(toChild[0],1) == 1) 最后,您的父进程应循环遍历argv []中的每个参数,并将每个参数作为strlen大小的缓冲区发送. 我几乎可以肯定这就是你想要做的.请注意,为了在知道哪个描述符用于特定目的时保持健全,我更喜欢使用#define来记录每个进程用于读写的内容.这可以扩展到任何数量的进程,顺便说一下,我确信你的下一个任务不会太过分: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <signal.h> // P0_READ - parent read source // P0_WRITE - parent write target // P1_READ - child read source // P1_WRITE - child write target #define P0_READ 0 #define P1_WRITE 1 #define P1_READ 2 #define P0_WRITE 3 #define N_PIPES 4 int main(int argc,char **argv) { int fd[N_PIPES],count = 0,i; pid_t pid; char c; if (pipe(fd) || pipe(fd+2)) { perror("Failed to open pipe(s)"); return EXIT_FAILURE; } // fork child process if ((pid = fork()) == -1) { perror("Failed to fork child process"); return EXIT_FAILURE; } // child process if (pid == 0) { // close non P1 descriptors close(fd[P0_READ]); close(fd[P0_WRITE]); // get chars from input pipe,counting each one. while(read(fd[P1_READ],&c,1) == 1) count++; printf("Child: count = %dn",count); write(fd[P1_WRITE],sizeof(count)); // close remaining descriptors close(fd[P1_READ]); close(fd[P1_WRITE]); return EXIT_SUCCESS; } // parent process. start by closing unused descriptors close(fd[P1_READ]); close(fd[P1_WRITE]); // send each arg for (i=1; i<argc; ++i) write(fd[P0_WRITE],argv[i],strlen(argv[i])); // finished sending args close(fd[P0_WRITE]); // Wait for child process to return. wait(NULL); // wait for total count if (read(fd[P0_READ],sizeof(count)) == sizeof(count)) printf("Parent: count = %dn",count); // close last descriptor close(fd[P0_READ]); return 0; } 输入 ./progname argOne argTwo 产量 Child: count = 12 Parent: count = 12 编辑:具有子返回状态的单个管道 从原始问题的评论看来,您的任务可能会要求将子进程的返回状态作为结果计数而不是将其返回到管道中.这样做,您可以使用单个管道描述符对完成此操作.我更喜欢第一种方法,但这也适用: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <signal.h> // P0_WRITE - parent write target // P1_READ - child read source #define P1_READ 0 #define P0_WRITE 1 #define N_PIPES 2 int main(int argc,count = 0; pid_t pid; char c; if (pipe(fd)) { perror("Failed to open pipe(s)"); return EXIT_FAILURE; } // fork child process pid = fork(); if (pid == -1) { perror("Failed to fork child process"); return EXIT_FAILURE; } if (pid == 0) { // close non P1 descriptors close(fd[P0_WRITE]); // Return number of characters counted to parent process. while(read(fd[P1_READ],1) == 1) ++count; close(fd[P1_READ]); printf("Child: count = %dn",count); return count; } // parent process. start by closing unused descriptors close(fd[P1_READ]); // eacn each arg entirely for (int i=1; i<argc; ++i) write(fd[P0_WRITE],strlen(argv[i])); // finished sending args close(fd[P0_WRITE]); // Wait for child process to return. if (wait(&count) == -1) { perror("Failed to wait for child process"); return EXIT_FAILURE; } printf("Parent: count = %dn",WEXITSTATUS(count)); return 0; } 结果是一样的,但请注意这是一个调试的biach,因为大多数调试器将在您的子进程上发出信号跳闸并且实际退出状态丢失.例如,在我的Mac上,在Xcode游戏下运行: Failed to wait for child process: Interrupted system call 从命令行运行时给出: Child: count = 12 Parent: count = 12 我更喜欢双管方法的众多原因之一. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |