Общение между родителем, ребенком и внуком в C - PullRequest
0 голосов
/ 23 февраля 2020

Поэтому я пытаюсь настроить связь между родителем (компьютерная система) и его дочерним (системная шина), а также между дочерним (системная шина) и внуком (устройство ввода-вывода). Я не пытаюсь установить связь между родителем и внуком. Мой код работал нормально, когда он был только родителем и потомком, однако, когда я добавил в каналы для child-> grandchild and grandchild-> child, он не работает; в частности, внук не может общаться с ребенком.

Я поместил «<---- ОШИБКА», где код, который я добавляю, останавливает программу и завершает работу. Без этих строк программа работает, но общаются только родитель и ребенок. Я делаю это неправильно? Или есть тонкая ошибка, которую я пропускаю? </p>

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

Вот мой код:

#include <stdio.h>
#include <unistd.h> 
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

void computer_system    (int pipe_cpu_bus[], int pipe_bus_cpu[], int length);
void system_bus         (int pipe_cpu_bus[], int pipe_bus_cpu[], char *filename);
void io_device          (int pipe_bus_io[], int pipe_io_bus[], char *filename);
void transfer_device    (int pipe_bus_tran[]);
void buffer             (int pipe_bus_buf[]);

#define MSGSIZE 20 

int 
main (int argc, char **argv) {
    // a pipe from cpu to bus, 
    // use 1 within cpu to write to bus
    // use 0 within bus to read from cpu
    int pipe_cpu_bus[2];
    // a pipe from bus to cpu, 
    // use 1 within bus to write to cpu 
    // use 0 within cpu to read from bus
    int pipe_bus_cpu[2];

    // error checking for pipe 
    if (pipe(pipe_cpu_bus) < 0) 
        exit(1); 
    if (pipe(pipe_bus_cpu) < 0) 
        exit(1);

    // error checking for fcntl 
    if (fcntl(pipe_cpu_bus[0], F_SETFL, O_NONBLOCK) < 0) 
        exit(2); 
    if (fcntl(pipe_bus_cpu[0], F_SETFL, O_NONBLOCK) < 0) 
        exit(2); 

    switch (fork()) { 
        // error 
        case -1: 
            exit(3); 

        // child process (COMPUTER SYSTEM)
        case 0: 
            if (argc >= 3) {
                int length = atoi(argv[2]);
                computer_system(pipe_cpu_bus, pipe_bus_cpu, length);
            }
            else {
                printf("Usage: %s <file_name> <number>", argv[0]);
            }
            break; 

        // parent process (SYSTEM BUS)
        default: 
            if (argc >= 3) {
                char* filename = argv[1];
                system_bus(pipe_cpu_bus, pipe_bus_cpu, filename);
            }
            else {
                printf("Usage: %s <file_name> <number>", argv[0]);
            }
            break; 
    } 

    return 0; 
}

void
computer_system (int pipe_cpu_bus[], int pipe_bus_cpu[], int length) {
    int nread;
    char buf[MSGSIZE];

    close(pipe_cpu_bus[0]); // close read end of cpu_bus
    close(pipe_bus_cpu[1]); // close write end of bus_cpu

    write(pipe_cpu_bus[1], "hello", 5);

    while (1) {
        memset(buf, 0, sizeof buf);
        nread = read(pipe_bus_cpu[0], buf, MSGSIZE);
        switch (nread) {
            // case -1 means pipe is empty and errono set EAGAIN 
            case -1:
                if (errno == EAGAIN) {
                    printf("  (pipe empty in cpu)\n");
                    sleep(1);
                    break;
                }
                else {
                    perror("read");
                    exit(4);
                }

            // case 0 means all bytes are read and EOF (end of conv.)  
            case 0:
                close(pipe_bus_cpu[0]);
                close(pipe_cpu_bus[1]);
                exit(0);

            // some bytes have been read
            default:
                printf("bus: %s\n", buf);
                write(pipe_cpu_bus[1], "hello", 5);
                sleep(1);
        }
    }

    exit(0);
}

void
system_bus (int pipe_cpu_bus[], int pipe_bus_cpu[], char *filename) {

    // ======== CREATE IO PROCESS ========

    int pipe_io_bus[2], pipe_bus_io[2];

    // error checking for pipe 
    if (pipe(pipe_io_bus) < 0) 
        exit(1); 
    if (pipe(pipe_bus_io) < 0) 
        exit(1);

    // error checking for fcntl 
    if (fcntl(pipe_io_bus[0], F_SETFL, O_NONBLOCK) < 0) 
        exit(2); 
    if (fcntl(pipe_bus_io[0], F_SETFL, O_NONBLOCK) < 0) 
        exit(2); 

    switch (fork()) { 
        // error 
        case -1: 
            exit(3); 

        // child process (COMPUTER SYSTEM)
        case 0: 
            io_device(pipe_io_bus, pipe_bus_io, filename);
            break; 

        default:
            break;
    } 
    // ===================================

    int nread;
    char buf[MSGSIZE];

    close(pipe_cpu_bus[1]); // close write end of cpu_bus
    close(pipe_bus_cpu[0]); // close read end of bus_cpu

    close(pipe_io_bus[1]);  // <--- ERROR
    close(pipe_bus_io[0]);  // <--- ERROR

    while (1) {
        // ==== Read from IO ====
        memset(buf, 0, sizeof buf);
        nread = read(pipe_io_bus[0], buf, MSGSIZE);
        switch (nread) {
            // case -1 means pipe is empty and errono set EAGAIN 
            case -1:
                if (errno == EAGAIN) {
                    printf("  (io pipe empty in bus)\n");
                    sleep(1);
                    break;
                }
                else {
                    perror("read");
                    exit(4);
                }

            // case 0 means all bytes are read and EOF (end of conv.)  
            case 0:
                close(pipe_io_bus[0]);
                close(pipe_bus_io[1]);
                exit(0);

            // some bytes have been read
            default:
                printf("io: %s\n", buf);
                write(pipe_bus_io[1], "fuck off", 8);
                sleep(1);
        }

        // ==== Read from CPU ====
        memset(buf, 0, sizeof buf);
        nread = read(pipe_cpu_bus[0], buf, MSGSIZE);
        switch (nread) {
            // case -1 means pipe is empty and errono set EAGAIN 
            case -1:
                if (errno == EAGAIN) {
                    printf("  (cpu pipe empty in bus)\n");
                    sleep(1);
                    break;
                }
                else {
                    perror("read");
                    exit(4);
                }

            // case 0 means all bytes are read and EOF (end of conv.)  
            case 0:
                close(pipe_cpu_bus[0]);
                close(pipe_bus_cpu[1]);
                exit(0);

            // some bytes have been read
            default:
                printf("cpu: %s\n", buf);
                write(pipe_bus_cpu[1], "fuck off", 8);
                sleep(1);
        }
    }
}

void 
io_device (int pipe_bus_io[], int pipe_io_bus[], char *filename) {
    int nread;
    char buf[MSGSIZE];

    close(pipe_io_bus[0]); // close read end of bus_io
    close(pipe_bus_io[1]); // close write end of io_bus

    write(pipe_io_bus[1], "here is a message", 17);

    while (1) {
        memset(buf, 0, sizeof buf);
        nread = read(pipe_bus_io[0], buf, MSGSIZE);
        switch (nread) {
            // case -1 means pipe is empty and errono set EAGAIN 
            case -1:
                if (errno == EAGAIN) {
                    printf("  (pipe empty in io)\n");
                    sleep(1);
                    break;
                }
                else {
                    perror("read");
                    exit(4);
                }

            // case 0 means all bytes are read and EOF (end of conv.)  
            case 0:
                close(pipe_bus_io[0]);
                close(pipe_io_bus[1]);
                exit(0);

            // some bytes have been read
            default:
                printf("bus: %s\n", buf);
                write(pipe_io_bus[1], "here is a message", 17);
                sleep(1);
        }
    }
}

Как вы можете видеть, без этих двух строк, которые вызывают Программа для выхода по неизвестной причине работает, но шина (дочерняя) ничего не получает от io (внука), несмотря на то, что io явно пишет в нее.

Если две строки не пропущены, печать отладки выглядит следующим образом:

  (pipe empty in cpu)
  (io pipe empty in bus)
  (pipe empty in cpu)
cpu: hello
bus: fuck off

Вот выходные данные отладки, если вам это требуется.

  (pipe empty in cpu)
  (io pipe empty in bus)
  (pipe empty in io)
  (pipe empty in cpu)
  (pipe empty in io)
cpu: hello
bus: fuck off
  (pipe empty in io)
  (io pipe empty in bus)
  (pipe empty in cpu)
  (pipe empty in io)
cpu: hello
bus: fuck off
  (io pipe empty in bus)
  (pipe empty in io)
  (pipe empty in cpu)
cpu: hello
  (pipe empty in io)
^C⏎

1 Ответ

1 голос
/ 23 февраля 2020

Я прошу прощения за то, что потратил ваше время,

В конце я отправил аргументы в io_device () в неправильном порядке, закрыв тем самым неверные конечные каналы. Поэтому я писал в канал, который закрылся, что привело к сбою программы.

Изменение объявления функции io_device с

void io_device (pipe_bus_io[], pipe_io_bus[], char *filename) {}

на

void io_device (pipe_io_bus[], pipe_bus_io[], char *filename) {}

решило проблему.

Опять же, я прошу прощения, эти мелкие детали ускользнули от меня, несмотря на то, что я искал их часами подряд. Я думаю, что написание этого вопроса заставило меня взглянуть на него по-другому.

Спасибо Тэдман и Дэвид за помощь!

...