Linux
為什麼 grep 在這裡返回 SIGPIPE(信號 13)?
我必須創建一個程序,其中我有 P0 作為父程序和 P1,…,PN 子程序。每個孩子都必須在文件中執行 grep 並在管道中返回輸出。然後 P0 必須讀取消息併計算行數並將包含該數字的句子列印到標準輸出中。問題是每個孩子都會不由自主地被信號 13 終止。為什麼會發生這種情況?這是我的程式碼:
#include <fcntl.h> #include <stdio.h> #include <unistd.h> #include <signal.h> #include <stdlib.h> #include <string.h> #include <sys/wait.h> //eventuali define #define MAXDIM 255 #define MAXPID 30 //global var declaration int fd; int pipefd[MAXPID][2]; //func declaration void print_usage(char* prog_name); void wait_child(); void codice_figlio(int index, char *word, char *filename); void handler(int signo); int conta_righe(char *str); int main(int argc, char *argv[]) { // local var declaration int N = argc - 2; int pid[MAXPID]; int i, num; char buf[MAXDIM]; if (argc < 3) { fprintf(stderr, "Numero di parametri non valido\n"); print_usage(argv[0]); exit(EXIT_FAILURE); } for (i = 1; i <= N; i++) { if ((fd = open(argv[i], O_RDONLY)) < 0) { perror("Errore nell'apertura del file"); exit(EXIT_FAILURE); } close(fd); } signal(SIGUSR1, handler); for (i = 0; i < N; i++) { pid[i] = fork(); if (pipe(pipefd[i]) < 0) exit(-3); if (!pid[i]) { pause(); codice_figlio(i, argv[argc - 1], argv[i + 1]); } else if (pid[i] < 0) { perror("fork error"); exit(-3); } sleep(1); kill(pid[i], SIGUSR1); close(pipefd[i][1]); read(pipefd[i][0], buf, sizeof(int)); num = conta_righe(buf); printf("Nel file %s sono state trovate %d occorrenze di %s.\n", argv[i + 1], num, argv[argc - 1]); } for (i = 0; i < N; i++) { wait_child(); close(pipefd[i][0]); close(pipefd[i][1]); } return 0; } void print_usage(char* prog_name){ fprintf(stderr, "Usage:\n\t%s file1 file2 ... fileN parola\n", prog_name); } void wait_child() { int status, pid; pid = wait(&status); printf("*P0 (pid = %d): Terminato processo figlio PID = %d: ", getpid(), pid); if ((char)status == 0) printf("Terminazione volontaria con stato %d\n", status>>8); else printf("Terminazione involontaria per segnale %d\n", (char)status); } void codice_figlio(int index, char *word, char *filename) { close(pipefd[index][0]); close(1); dup(pipefd[index][1]); close(pipefd[index][1]); execlp("/bin/grep", "grep", word, filename, (char*)0); perror("Problemi con la grep"); exit(EXIT_FAILURE); } void handler(int signo) { return; } int conta_righe(char *str) { int res = 0, i = 0; while (str[i] != '\0') { if (str[i] == '\n') res++; i++; } return res; }
移動.
if (pipe(pipefd[i]) < 0)
_fork()
否則,您只是創建兩個單獨的管道(在父級和子級中),SIGPIPE
當您關閉子級(在codice_figlio()
函式中)管道的寫入端時,您將得到一個,因為它是對它的唯一引用,而不是父子之間共享的描述符。這不是唯一的問題。
read(pipefd[i][0], buf, sizeof(int));
已損壞,因為您只會從管道中讀取 4 個字節,但您的conta_righe()
函式會嘗試計算其中的行數。將 更改sizeof(int)
為sizeof buf
。在此之後,您的程式碼似乎做了一些明智的事情:
$ ./fo fo.c fo.c pipefd Nel file fo.c sono state trovate 8 occorrenze di pipefd. Nel file fo.c sono state trovate 8 occorrenze di pipefd. *P0 (pid = 9541): Terminato processo figlio PID = 9542: Terminazione volontaria con stato 0 *P0 (pid = 9541): Terminato processo figlio PID = 9543: Terminazione volontaria con stato 0
這是您程式碼的更新檔(手動應用,此站點會破壞標籤):
--- fo.c~ 2020-04-20 20:51:19.540914204 +0300 +++ fo.c 2020-04-20 20:51:22.648914269 +0300 @@ -42,8 +42,8 @@ } signal(SIGUSR1, handler); for (i = 0; i < N; i++) { - pid[i] = fork(); if (pipe(pipefd[i]) < 0) exit(-3); + pid[i] = fork(); if (!pid[i]) { pause(); codice_figlio(i, argv[argc - 1], argv[i + 1]); @@ -55,7 +55,7 @@ sleep(1); kill(pid[i], SIGUSR1); close(pipefd[i][1]); - read(pipefd[i][0], buf, sizeof(int)); + read(pipefd[i][0], buf, sizeof(buf)); num = conta_righe(buf); printf("Nel file %s sono state trovate %d occorrenze di %s.\n", argv[i + 1], num, argv[argc - 1]); }