Двусторонняя связь с трубами

Мне нужно создать связь между родителем и разветвленным дочерним элементом с помощью каналов. Родитель отправит 0, потомок отправит обратно 1, родитель ответит 2 и т. д., пока счетчик не достигнет 5. Затем оба процесса завершатся.

Я попытался реализовать это с помощью двух каналов:

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

int main(int argc, char *argv[])
{
    int fd[2];
    int fd2[2];

    int val = 0;

    // create pipe descriptors
    pipe(fd);
    pipe(fd2);

    // fork() returns 0 for child process, child-pid for parent process.
    if (fork() != 0) {
            ///0. Send: 0
            // parent: writing only, so close read-descriptor.
            close(fd[0]);

            // send the value on the write-descriptor.
            val = 0;
        resend:
            write(fd[1], &val, sizeof(val));
            printf("0.Parent(%d) send value: %d\n", getpid(), val);

            // close the write descriptor
            close(fd[1]);

            ///3. Receive 1;
            close(fd2[1]);

            // now read the data
            read(fd2[0], &val, sizeof(val));
            printf("3.Parent(%d) received value: %d\n", getpid(), val);

            // close the read-descriptor
            close(fd2[0]);
            wait(NULL);
            val++;
            if (val < 6)
                goto resend;
            else
                return 0;

    } else {   // child: reading only, so close the write-descriptor
        childStart:
        wait(NULL);

        ///1. receive: 0
            close(fd[1]);

            // now read the data (will block)
            read(fd[0], &val, sizeof(val));
            printf("1.Child(%d) received value: %d\n", getpid(), val);

            // close the read-descriptor
            //close(fd[0]);

            ///2. Send: 1
            // parent: writing only, so close read-descriptor.
            close(fd2[0]);

            // send the value on the write-descriptor.
            val = val + 1;
            write(fd2[1], &val, sizeof(val));
            printf("2.Child(%d) send value: %d\n", getpid(), val);

            // close the write descriptor
            close(fd2[1]);
            if(val <5) {
                wait(NULL);
                goto childStart;
            }
            else
                return 0;
        }
        ///////////////////////////////////////////////////////////////////////////////////

    return 0 ;
    }

Я получаю следующий вывод:

0.Parent(120978) send value: 0
1.Child(120979) received value: 0
2.Child(120979) send value: 1
1.Child(120979) received value: 1
2.Child(120979) send value: 2
1.Child(120979) received value: 2
2.Child(120979) send value: 3
1.Child(120979) received value: 3
2.Child(120979) send value: 4
1.Child(120979) received value: 4
2.Child(120979) send value: 5
3.Parent(120978) received value: 1
0.Parent(120978) send value: 2
3.Parent(120978) received value: 2
0.Parent(120978) send value: 3
3.Parent(120978) received value: 3
0.Parent(120978) send value: 4
3.Parent(120978) received value: 4
0.Parent(120978) send value: 5
3.Parent(120978) received value: 5

Как я могу заставить процессы ждать сообщения друг друга?


person David    schedule 22.05.2020    source источник
comment
resend: if (val < 6) goto resend; Просто используйте цикл while... Вы выполняете close(fd[1]);, затем goto resend и повторно используете write(fd[1],. Ну, как только вы закроете fd[1], вы не сможете использовать его позже.   -  person KamilCuk    schedule 22.05.2020
comment
Re Как я могу заставить процессы ждать сообщения друг друга? Что вы имеете в виду? Вы ясно видите, как родитель ждет ответа, прежде чем отправить следующий номер. То же у ребенка   -  person ikegami    schedule 22.05.2020
comment
Вы закрываете дескрипторы файлов в цикле, который все ломает; и вы не проверяете коды выхода из операций чтения/записи, поэтому после закрытия файловых дескрипторов каждое чтение/запись не блокируется и возвращает ошибку, что означает, что переменная не отправляется и не перезаписывается.   -  person Petesh    schedule 22.05.2020
comment
Почему вы называете wait в ребенке?   -  person William Pursell    schedule 22.05.2020


Ответы (1)


В вашем коде много проблем, я много чего поменял, результат такой:

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

int main(int argc, char *argv[])
{
    int signo;
    pid_t child_pid,parent_pid;
    sigset_t newmask;
    int fd[2];
    int fd2[2];

    int val = 0;

    // create pipe descriptors
    pipe(fd);
    pipe(fd2);

    // create mask for SIGUSR1
    sigemptyset(&newmask);
    sigaddset(&newmask,SIGUSR1);
    sigaddset(&newmask,SIGUSR2);
    sigprocmask(SIG_BLOCK,&newmask,NULL);

    parent_pid = getpid();

    // fork() returns 0 for child process, child-pid for parent process.
    if ((child_pid = fork()) != 0) {
      // Close unused file descriptors
      close(fd[0]);
      close(fd2[1]);

      // send the value on the write-descriptor.
      for(val = 0; val < 6; val++){
        write(fd[1], &val, sizeof(val));
        printf("0.Parent(%d) send value: %d\n", getpid(), val);
        sigwait(&newmask,&signo);
        kill(parent_pid,SIGUSR2);

        // now read the data
        read(fd2[0], &val, sizeof(val));
        printf("3.Parent(%d) received value: %d\n", getpid(), val);
        sigwait(&newmask,&signo);
        kill(parent_pid,SIGUSR2);
      }

      return 0;

    } else {   // child: reading only, so close the write-descriptor
      // Closing unused file descriptors
      close(fd[1]);
      close(fd2[0]);


      for(; val <= 5; val++){
        // now read the data (will block)
        read(fd[0], &val, sizeof(val));
        printf("1.Child(%d) received value: %d\n", getpid(), val);
        kill(child_pid,SIGUSR1);
        sigwait(&newmask,&signo);

        // send the value on the write-descriptor.
        write(fd2[1], &val, sizeof(val));
        printf("2.Child(%d) send value: %d\n", getpid(), val);
        kill(child_pid,SIGUSR1);
        sigwait(&newmask,&signo);
      }

      wait(NULL);

      return 0;
    }
}

Ваши ошибки:

выход:

0.Parent(14956) send value: 0
1.Child(14957) received value: 0
2.Child(14957) send value: 0
3.Parent(14956) received value: 0
0.Parent(14956) send value: 1
1.Child(14957) received value: 1
2.Child(14957) send value: 1
3.Parent(14956) received value: 1
0.Parent(14956) send value: 2
1.Child(14957) received value: 2
2.Child(14957) send value: 2
3.Parent(14956) received value: 2
0.Parent(14956) send value: 3
1.Child(14957) received value: 3
2.Child(14957) send value: 3
3.Parent(14956) received value: 3
0.Parent(14956) send value: 4
1.Child(14957) received value: 4
2.Child(14957) send value: 4
3.Parent(14956) received value: 4
0.Parent(14956) send value: 5
1.Child(14957) received value: 5
2.Child(14957) send value: 5
3.Parent(14956) received value: 5
person Holeryn    schedule 26.05.2020