Использование двух каналов для связи между родительским процессом и дочерним процессом - PullRequest
0 голосов
/ 07 февраля 2020

Проблема

Я получаю это только на выходе терминала. Я считаю, что программа застревает при вызове fork(), но я не знаю точно, почему.

Название программы q9:

prompt>$ ./q9 inputString
Parent: writing to pipe 'inputString'

Task

  • чтение ввода с терминала в канал «родитель-потомок».
  • fork () для создания дочернего процесса.
  • чтение входных данных из канала «родитель-потомок».
  • объединяет некоторую другую строку с этой строкой, считываемой из канала.
  • записать новую сцепленную строку в канал «потомок-родитель».
  • в родительском канале, прочитать из канала «потомок» и распечатать выходные данные, прочитанные из канала в терминал. .

Попытки

Я пытался исправить это:

  • , пытаясь закрыть трубы в разных местах. Я подумал, что, возможно, что-то пропустил или оставил что-то открытым, но я так не думаю.
  • помещает wait () в родительский объект, потому что, возможно, он не давал ребенку полностью запустить
  • попытался напечатать вывод объединенной строки на случай, если это испортит отпечатки.

Код

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/wait.h>

int main (int argc, char *argv[]) {
    // parent RUN
    if(argc == 1) {
        printf("usage: q9 <string>\n");
        return 0;
    }

    // create two way pipes
    int parent_fds[2], child_fds[2];

    // create strings to save too
    char fromParent[100];
    char fromChild[100];

    // read:[0] - write:[1]
    if (pipe(parent_fds) != 0 && pipe(child_fds) != 0) {
        fprintf(stderr, "pipes failed!\n");
    }

    // close unused pipe end by parent
    close(parent_fds[0]);
    close(child_fds[1]);
    close(child_fds[0]);

    // write from terminal to parent pipe FOR child to read
    printf("Parent: writing to pipe '%s'\n", argv[1]);
    write(parent_fds[1], argv[1], strlen(argv[1]));
    close(parent_fds[1]);

    // fork() child process
    int child = fork();

    // NEVER GETS PASSED HERE :(

    if (child < 0) {
        fprintf(stderr, "fork failed!");
        exit(1);
    } else if (child == 0) {
        printf("I reached the child :)");
        // close unwanted pipe ends by child
        close(child_fds[0]);
        close(parent_fds[1]);

        // read from parent pipe
        int n = read(parent_fds[0], fromParent, 100);
        fromParent[n] = 0;
        printf("Child: reading from parent pipe '%s'\n", fromParent);
        close(parent_fds[0]);

        // Concatinate to what was read in
        const char myText[14] = " (added this.)";
        strcat(fromParent, myText);

        write(child_fds[1], fromParent, strlen(fromParent));
        close(child_fds[1]);
        printf("Child: writing to pipe - '%s'\n", fromParent);
    } else {
        // read from child pipe
        int n = read(child_fds[0], fromChild, 100);
        fromChild[n] = 0;
        printf("Parent: reading from pipe - '%s'\n", fromChild);
    }

    return 0;
}

Что не так?

1 Ответ

2 голосов
/ 07 февраля 2020

Было несколько проблем, и ваши сообщения о диагностике c не гарантировались. Убедитесь, что вы заканчиваете свои сообщения новыми строками.

  1. Вы создали только один канал, потому что вы использовали && вместо ||.
  2. Вы закрыли каналы "для родителя" до того, как вы создали ребенка (также отмечено kaylum в комментарии ).

В приведенном ниже коде есть несколько других очисток. Код (все еще) не гарантирует, что операции записи в канал были успешными (раньше они не выполнялись). Это гарантирует, что строки, считываемые из каналов, не длиннее буферов, в которые они помещены; это не гарантирует, что есть достаточно места, чтобы добавить дополнительную информацию в ребенка. Показанный код ожидает завершения всех дочерних процессов перед выходом. Дочерний выполняет вызов wait(), но он немедленно завершается неудачей (и дочерний элемент ничего не печатает) и завершается. Родитель ожидает завершения работы ребенка и сообщает об этом перед выходом.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    if (argc == 1)
    {
        fprintf(stderr, "Usage: %s <string>\n", argv[0]);
        return EXIT_FAILURE;
    }

    // create two pipes:
    // - parent_fds used by parent to write to child
    // - child_fds used by child to write to parent
    int parent_fds[2], child_fds[2];

    // read:[0] - write:[1]
    if (pipe(parent_fds) != 0 || pipe(child_fds) != 0)  /* || not && */
    {
        fprintf(stderr, "pipes failed!\n");
        return EXIT_FAILURE;
    }

    // fork() child process
    int child = fork();

    if (child < 0)
    {
        fprintf(stderr, "fork failed!");
        return EXIT_FAILURE;
    }
    else if (child == 0)
    {
        printf("%d: I reached the child :)\n", (int)getpid());
        // close unwanted pipe ends by child
        close(child_fds[0]);
        close(parent_fds[1]);

        // read from parent pipe
        char fromParent[100];
        int n = read(parent_fds[0], fromParent, sizeof(fromParent) - 1);
        fromParent[n] = '\0';
        printf("%d: Child: read from parent pipe '%s'\n", (int)getpid(), fromParent);
        close(parent_fds[0]);

        // Append to what was read in
        strcat(fromParent, " (added this.)");

        write(child_fds[1], fromParent, strlen(fromParent));
        close(child_fds[1]);
        printf("%d: Child: writing to pipe - '%s'\n", (int)getpid(), fromParent);
    }
    else
    {
        // close unwanted pipe ends by parent
        close(parent_fds[0]);
        close(child_fds[1]);

        // write from terminal to parent pipe FOR child to read
        printf("%d: Parent: writing to pipe '%s'\n", (int)getpid(), argv[1]);
        write(parent_fds[1], argv[1], strlen(argv[1]));
        close(parent_fds[1]);
        // read from child pipe
        char fromChild[100];
        int n = read(child_fds[0], fromChild, sizeof(fromChild) - 1);
        fromChild[n] = '\0';
        close(child_fds[0]);
        printf("%d: Parent: read from pipe - '%s'\n", (int)getpid(), fromChild);
    }

    int corpse;
    int status;
    while ((corpse = wait(&status)) > 0)
        printf("%d: child PID %d exited with status 0x%.4X\n", (int)getpid(), corpse, status);

    return EXIT_SUCCESS;
}

Пример вывода (источник pipe43.c, программа pipe43):

$ pipe43 'Nobody expects the Spanish Inquisition!'
84543: Parent: writing to pipe 'Nobody expects the Spanish Inquisition!'
84544: I reached the child :)
84544: Child: read from parent pipe 'Nobody expects the Spanish Inquisition!'
84544: Child: writing to pipe - 'Nobody expects the Spanish Inquisition! (added this.)'
84543: Parent: read from pipe - 'Nobody expects the Spanish Inquisition! (added this.)'
84543: child PID 84544 exited with status 0x0000
$
...