Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Two-way communication with pipes

I need to create communication between parent and a forked child using pipes. The parent will send 0, the child will send back 1, the parent will reply 2, etc., until the counter reaches 5. Then both processes will terminate.

I tried to implement this using two pipes:

#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 ;
    }

I get the follow output:

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

How can I make the processes wait for each other's message?

like image 925
David Avatar asked Oct 23 '25 17:10

David


1 Answers

Thera are a lot of problems in your code, i changed a lot of things, the result is this:

#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;
    }
}

Your mistakes:

  • you tried to write on closed file descriptors
  • you don't created any type of syncronyzation between the child and the parent: for create this i used sigwait() (https://www.man7.org/linux/man-pages/man3/sigwait.3.html) and kill (https://www.man7.org/linux/man-pages/man2/kill.2.html),
  • you used wait(NULL) in child and in other places where it was useless
  • you created spaghetti code, this is not a real mistake, but don't use goto instead of loops.

output:

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
like image 85
Holeryn Avatar answered Oct 26 '25 07:10

Holeryn



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!