C — Отправка данных туда и обратно между процессами

#c #pipe #fork #ipc

#c #канал #форк #ipc

Вопрос:

Я работаю над приведенной ниже программой. Предполагается, что он получает случайное значение int из дочернего процесса и, в зависимости от переменной item_count, возвращает соответствующее сообщение дочернему процессу с помощью каналов. Проблема в том, что я получаю много неожиданного поведения при выполнении, см. Ниже. myCatalog — это структура.

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

struct catalog {
    char description[128];
    int price;
    int item_count;
};

int main() {
    int i, j, k, fd1[5][2], fd2[5][2];
    struct catalog myCatalog[3];
    pid_t pid;
    int itemNo;
    char message[24];
    char messageFailure[] = "Failure.", messageSuccess[] = "Success!";;        

 

    for(i = 0; i < 5; i  ) {
        if(pipe(fd1[i]) == -1) {
                printf("Error opening pipe 1!n");
                exit(1);
        }

        if(pipe(fd2[i]) == -1) {
            printf("Error opening pipe 2!n");
            exit(1);
        }

        pid = fork();

        if(pid == 0) { //Child
            time_t t;
            srand((int)time(amp;t) % getpid());
            
            close(fd1[i][0]);  //Close reading end of fd1
            close(fd2[i][1]);  //Close writing end of fd2
            
            for(k = 0; k < 10; k  ) {
                itemNo = rand() % 21;
                write(fd1[i][1], amp;itemNo, sizeof(int));
                sleep(1);
                read(fd2[i][0], message, sizeof(message));
                printf("%sn", message);
            }
            printf("Hello from child process %dn", getpid());
            close(fd1[i][1]);
            close(fd2[i][0]);
            exit(0);
        }
        else if(pid > 0) { //Parent
            int item;

            close(fd1[i][1]);  //Close writing end of fd1
            close(fd2[i][0]);  //Close reading end of fd2

            if(i == 0) {
                for(j = 0; j < 20; j  ) {
                    snprintf(myCatalog[j].description, sizeof(myCatalog[j].description), "Item #%d", j);
                    myCatalog[j].price = (rand() % 10)   1;
                    myCatalog[j].item_count = 2;
                }
                for(j = 0; j < 20; j  ) {
                    printf("Description: %sn", myCatalog[j].description);
                    printf("Price: %dn", myCatalog[j].price);
                    printf("Count: %dn", myCatalog[j].item_count);
                }   
            }
            for(j = 0; j < 10; j  ) {
                read(fd1[i][0], amp;item, sizeof(int));
                printf("%dn", item);
                myCatalog[item].item_count = myCatalog[item].item_count - 1;
                if(myCatalog[item].item_count <= 0) {
                    write(fd2[i][1], messageFailure, sizeof(messageFailure));
                }
                else {
                    write(fd2[i][1], messageSuccess, sizeof(messageSuccess));                
                }
                sleep(1);
            }
            printf("Hello from parent process %dn", getpid());
            close(fd1[i][0]);
            close(fd2[i][1]);
            wait(NULL);
        }
        else {
            printf("Error forking!");
            exit(1);
        }

    }
    return 0;
}
 

Пример вывода для одного дочернего процесса выглядит следующим образом:

 Hello from parent process 11868
Hello from child process 11890
6
Success!
4
Success!
3
Success!
4
3
16
Success!
14
3
6
3
18
3
20
3
18
3
 

Что он должен сделать, это напечатать число, затем либо успех, либо сбой и т.д. Кроме того, иногда вместо 10 он выдает 13 чисел. Вопрос в том, в чем проблема? Это мой конвейер? Является ли мое использование цикла полностью неправильным?
Любая помощь будет принята с благодарностью.

Комментарии:

1. printf("error..." неверно. Попробуйте fprintf(stderr, "error...."); . Ошибки относятся к stderr.

2. Я не вижу «Успеха» нигде в вашем коде. Покажите полный пример. Включить main функцию и все #includes . Если бы я мог вырезать и вставить ваш код, я бы с удовольствием поиграл с ним. Я не хочу играть с ним в его текущем незавершенном состоянии.

3. @WilliamPursell это не является обязательным требованием. Это не похоже на то, что компьютер угадывает, является ли то, что вы печатаете, сообщением об ошибке, и если да, то не печатает его, если вы не используете stderr.

4. Приношу свои извинения за то, что добрался до вас так поздно, я обновил фрагмент, включив в него полную программу!

5. @user253751 Безусловно, верно, что компьютер не может догадаться, что сообщение является сообщением об ошибке, и отказывается печатать его в стандартный вывод. Это не меняет того факта, что печатать сообщения об ошибках в стандартный вывод некорректно. Во всяком случае, это делает более важным, чтобы программа поступала правильно. Сообщения об ошибках принадлежат stderr.

Ответ №1:

Это, конечно, выглядит неправильно. Доступ myCatalog[n] для n> 2 вызывает неопределенное поведение.

   struct catalog myCatalog[3];
  ...
  for(j = 0; j < 20; j  ) {
          printf("Description: %sn", myCatalog[j].description);
 

Комментарии:

1. О боже, я тестировал меньшие размеры, должно быть, я забыл его изменить. Большое вам спасибо за то, что заметили это, потому что я знаю, что никогда бы туда не заглянул!

2. Однако у меня есть продолжение. Теперь все печатается нормально, за исключением того, что иногда выводится ошибка для элемента, который не вызывался 2 раза. Является ли мой подход к этой части неправильным? Кажется, я неправильно вычитаю item_count. Еще раз большое вам спасибо и извините, если я жадничаю со своим вторым вопросом!

3. @sntovas Я бы предложил проверить значение, возвращаемое, read чтобы убедиться, что вы действительно получили значение.

4. Похоже, что поле item_price на самом деле не уменьшается, оно фактически принимает случайное значение, интересно, почему?