Pipe, Fork und Exec - Zwei-Wege-Kommunikation zwischen übergeordneten und untergeordneten Prozessen

Für eine Zuweisung in meiner Betriebssystemklasse muss ich einen binären Prozessbaum erstellen, indem ich exec in demselben Programm rekursiv aufrufe. Das Ziel ist es, eine beliebige Aufgabe in separate Prozesse aufzuteilen. Das Elternteil sollte mit den Kindern und die Kinder mit dem Elternteil nur über unbenannte Pipes kommunizieren. Die Idee ist, dass der Elternteil jedem Kind die Hälfte der Arbeit sendet, und dies wird rekursiv fortgesetzt, bis ein Basisfall erfüllt ist, bei dem die Länge der an jedes Kind übergebenen Zeichenfolge <= 2 ist. Das Kind verarbeitet dann diese Daten und sendet die Ergebnisse zurück zum Elternteil über Rohre.

Um zu verstehen, wie die bidirektionale Kommunikation mit Pipes in c funktioniert, habe ich das folgende einfache Programm erstellt, bevor ich mit der eigentlichen Aufgabe fortgefahren bin. Das übergeordnete Element liest jedoch nie die Daten aus dem untergeordneten Prozess. Ich erwarte die Ausgabe ...

im Elternteil | Nachricht erhalten: Test

Stattdessen erhalte ich beim Drucken ...

im Elternteil | Nachricht erhalten:

Es scheint, dass Buff leer ist und nicht aus dem Child-Prozess liest. Kann mir bitte jemand erklären, was ich falsch mache und / oder auf welche Weise

Schreiben an das ausführende Kind vom ElternteilLesen vom Elternteil im exekutierten KindRückschreiben an Eltern vom exekutierten KindLesen vom exekutierten Kind im Elternteil

Ich muss exec (), pipe (), fork () verwenden. Vielen Dank.

/**
 * *********************************
 * two_way_pipes.c
 * *********************************
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <math.h>
#include <sys/time.h> 
#include <sys/types.h> 
#include <unistd.h>

#define PARENT_READ read_pipe[0]
#define PARENT_WRITE write_pipe[1]
#define CHILD_WRITE read_pipe[1]
#define CHILD_READ  write_pipe[0]

#define DEBUGGING 1

int main(int argc, char **argv) {
    char buff[5];

    // in the child process that was exec'd on the orginal call to two_way_pipes
    if(argc == 2) {
        read(STDIN_FILENO, buff, 4); // this should read "test" from stdin
        buff[4] = '\0';
        fprintf(stdout, "%s\n", buff); // this should right "test" to stdout and be read by the parent process
    // int the root process, the original call to two_way_pipes with no args
    } else {
        int pid;
        int read_pipe[2];
        int write_pipe[2];

        pipe(read_pipe);
        pipe(write_pipe);

        pid = fork();

        // parent process
        if(pid > 0) {
            close(CHILD_READ);
            close(CHILD_WRITE);

            write(PARENT_WRITE, "test", 4); // attempting to write this to the child

            struct timeval tv;
            fd_set readfds;
            tv.tv_sec = 10;
            tv.tv_usec = 0;
            FD_ZERO(&readfds);
            FD_SET(PARENT_READ, &readfds);
            select(PARENT_READ + 1, &readfds, NULL, NULL, &tv);

            if(FD_ISSET(PARENT_READ, &readfds)) {
                read(PARENT_READ, buff, 4); // should read "test" which was written by the child to stdout
                buff[4] = '\0';
                close(PARENT_READ);
                close(PARENT_WRITE);
                fprintf(stderr, "in parent | message received: %s\n", buff);  // "test" is not in buff
            }

        // child process
        } else if(pid == 0) {
            close(PARENT_READ);
            close(PARENT_WRITE);

            dup2(CHILD_READ, STDIN_FILENO);
            dup2(CHILD_WRITE, STDOUT_FILENO);
            close(CHILD_READ);
            close(CHILD_WRITE);

            char *argv2[] = {"some random arg to make sure that argc == 2 in the child", NULL};
            execvp("two_way_pipes", argv2);
            _exit(0);
        // error forking child process
        } else {
            fprintf(stderr, "error forking the child\n");
        }
    }
}

Aktualisieren

Basierend auf Jonathons Antwort habe ich das arg2-Array geändert, das in execvp übergeben wird, um ...

char *argv2[] = {"two_way_pipes", "1", NULL};
execvp("two_way_pipes", argv2);

Dies hat das Problem nicht behoben. Der Elternteil konnte immer noch nicht "Test" vom Client zurücklesen. Als Reaktion auf Jonathons Antwort und Williams Kommentar fing ich an, meinen Exec-Aufruf zu optimieren, und aus irgendeinem Grund funktionierte es, ihn in die folgende Zeile zu ändern.

execl("two_way_pipes", "two_way_pipes", "1", NULL);

Ich akzeptiere gerne alle Antworten, die erklären, warum der execvp-Aufruf nicht funktioniert hat, aber der execl-Aufruf.

Antworten auf die Frage(3)

Ihre Antwort auf die Frage