0

So I have 2 questions about pipes in c :

1:

When i fork a process after creating a pipe in order to make the parent write to the pipe and the child read from it, How it's synchronized ? : the parent always send data before the child attempts to read that data although they are running concurrently? why i don't fall on the case where the child start reading before the parent try to send its data ?

2:

This is about file descriptors of the pipe, referring to the code below how can parent-process close the pipe-output file-descriptor while the child doesn't access to that file yet ? , assuming the parent starts first.

Any help will be appreciated, Thank you !

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

#define BUFFER_SIZE  256

int main(int argc , char*argv[])
{
pid_t  worker_pid ;
int descriptor[2];
unsigned char bufferR[256] , bufferW[256];

/***************************** create pipe ********************/

puts("pipe creation");
if (pipe(descriptor) !=0)
    {
        fprintf(stderr,"error in the pipe");
        exit(1);
    }

/***************************** create processes ********************/

puts("now fork processes");
worker_pid = fork(); // fork process 
if (worker_pid == -1 ) // error forking processes
    {
        fprintf(stderr,"error in fork");
        exit(2);
    }


/*********************** communicate processes ********************/

if (worker_pid == 0) // in the child process :  the reader
    {
     close(descriptor[1]); // close input file descriptor , ok because parent finished writing
     read(descriptor[0],bufferR,BUFFER_SIZE);
     printf("i'm the child process and i read : %s \n",bufferR);
    }


if (worker_pid !=0)
    {
       // is there any case where child attempts to read before parent writting ?
       close(descriptor[0]);// close file descriptor of child before it reads ?
       sprintf(bufferW,"i'm the parent process my id is %d , and i wrote this to my child",getpid());
       write(descriptor[1],bufferW,BUFFER_SIZE);
       wait(NULL); 
    }
    return 0;
}

I expected there will be some cases for question 1 where the output is : i'm the child process and i read :

because the parent doesn't wrote it's message yet

for question 2 i expected an error saying :

invalid file descriptor in the child process because the parent already closed it (assuming the parent runs always the first)

but the actual output is always : i'm the child process and i read: i'm the parent process my id is 7589, and i wrote this to my child

Saif Faidi
  • 509
  • 4
  • 15
  • 2
    You should read documentation http://man7.org/linux/man-pages/man7/pipe.7.html – Maxim Egorushkin Aug 01 '19 at 11:27
  • 3
    Possible duplicate of [How does a pipe work in Linux?](https://stackoverflow.com/q/1072125/608639) And related, [What is a simple explanation for how pipes work in Bash?](https://stackoverflow.com/q/9834086/608639) – jww Aug 01 '19 at 16:47
  • You don't seem to understand what happens during `fork()` with [file descriptors](https://en.wikipedia.org/wiki/Fork_(system_call)#Communication) and that the same file descriptor can be "active" in multiple processes. I would suggest reading some basic fork/IPC tutorial. – Stefan Becker Aug 02 '19 at 05:38

2 Answers2

2

When i fork a process after creating a pipe in order to make the parent write to the pipe and the child read from it, How it's synchronized ? : the parent always send data before the child attempts to read that data although they are running concurrently? why i don't fall on the case where the child start reading before the parent try to send its data ?

Typically, it doesn't need to be synchronized, and in fact it can itself serve as a synchronization mechanism. If you perform blocking reads (the default) then they will not complete until the corresponding data have been sent, regardless of the relative order of the initial read and write calls.

The two processes do, however, need to implement an appropriate mechanism to demarcate and recognize message boundaries, so that the reader can recognize and respond appropriately to short reads. That may be as simple as ending each message with a newline, and reading messages with fgets() (through a stream obtained via fdopen()).

This is about file descriptors of the pipe, referring to the code below how can parent-process close the pipe-output file-descriptor while the child doesn't access to that file yet ? , assuming the parent starts first.

Not an issue. Once the child is forked, it has access to the underlying open file descriptions it inherited from its parent, through the same file descriptor numbers that the parent could use, but these are separate from the parent for the purpose of determining how many times each open file description is referenced. The situation is similar to that resulting from the operation of the dup() syscall. Only when all processes close all their file descriptors for a given open file description is that open file description invalidated.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
1

This is done internally in the kernel. When you try to read from a file descriptor (being it a pipe, or socket), if the "remote side" has not sent any data, your process stalls (the call to read does not return at all), until the other side has pushed something into the internal buffers of the kernel (in your example, wrote to the pipe).

Here you can see the internal implementation of the pipes in linux: https://github.com/torvalds/linux/blob/master/fs/pipe.c#L272

Look for variable do_wakeup.

elcuco
  • 8,948
  • 9
  • 47
  • 69