Linux

為什麼 grep 在這裡返回 SIGPIPE(信號 13)?

  • April 21, 2020

我必須創建一個程序,其中我有 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]);
    }

引用自:https://unix.stackexchange.com/questions/581358