grepがここでSIGPIPE(信号13)を返すのはなぜですか?

grepがここでSIGPIPE(信号13)を返すのはなぜですか?

P0を親プロセスとして、P1、...、PNを子プロセスとして使用してプログラムを作成する必要があります。各子孫はファイルに対してgrepを実行し、パイプに出力を返す必要があります。その後、P0はメッセージを読み取り、行数を数え、その数を含む文をstdoutに印刷する必要があります。問題は、シグナル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;
}

ベストアンサー1

if (pipe(pipefd[i]) < 0)前に移動しますfork()。それ以外の場合は、2つの別々のパイプ(親と子)を作成し、子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]);
     }

おすすめ記事