5

It is known that during Interprocess Communication in Linux, the processes communicate with each other through a special file named as "Pipe".

It is also known that the the operations performed on that file is write by one process and read by one process in order to communicate with each other.

Now, the question is :

Do these write and read operations are performed in parallel during the communication (operations are executed parallely) ? and if not than,

What happens when one of the process enters the SLEEP state during the communication? Does it performs the write operation first for the second process to read or it goes directly to sleep without performing any of the write and read operation?

HarshitMadhav
  • 4,769
  • 6
  • 36
  • 45

1 Answers1

3

The sending process can write until the pipe buffer is full (64k on Linux since 2.6.11). After that, write(2) will block.

The receiving process will block until data is available to read(2).

For a more detailed look into pipe buffering, look at https://unix.stackexchange.com/a/11954.

For example, this program

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

int
main(int argc, char *argv[])
{
    int pipefd[2];
    pid_t cpid;
    char wbuf[32768];
    char buf[16384];

    /* Initialize writer buffer with 012...89 sequence */
    for (int i = 0; i < sizeof(wbuf); i++)
      wbuf[i] = '0' + i % 10;

    if (pipe(pipefd) == -1) {
        perror("pipe");
        exit(EXIT_FAILURE);
    }

    cpid = fork();
    if (cpid == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    }

    if (cpid == 0) {    /* Child reads from pipe */
        close(pipefd[1]);          /* Close unused write end */
        while (read(pipefd[0], &buf, sizeof(buf)) > 0);
        close(pipefd[0]);
        _exit(EXIT_SUCCESS);

    } else {            /* Parent writes sequence to pipe */
        close(pipefd[0]);          /* Close unused read end */
        for (int i = 0; i < 5; i++)
          write(pipefd[1], wbuf, sizeof(wbuf));
        close(pipefd[1]);          /* Reader will see EOF */
        wait(NULL);                /* Wait for child */
        exit(EXIT_SUCCESS);
    }
}

will produce the following sequence when run with gcc pipes.c && strace -e trace=open,close,read,write,pipe,clone -f ./a.out:

open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
close(3)                                = 0
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\320\3\2\0\0\0\0\0"..., 832) = 832
close(3)                                = 0
pipe([3, 4])                            = 0
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f32117489d0) = 21114
close(3)                                = 0
write(4, "01234567890123456789012345678901"..., 32768) = 32768
write(4, "01234567890123456789012345678901"..., 32768) = 32768
write(4, "01234567890123456789012345678901"..., 32768strace: Process 21114 attached
 <unfinished ...>
[pid 21114] close(4)                    = 0
[pid 21114] read(3, "01234567890123456789012345678901"..., 16384) = 16384
[pid 21114] read(3,  <unfinished ...>
[pid 21113] <... write resumed> )       = 32768
[pid 21114] <... read resumed> "45678901234567890123456789012345"..., 16384) = 16384
[pid 21113] write(4, "01234567890123456789012345678901"..., 32768 <unfinished ...>
[pid 21114] read(3, "01234567890123456789012345678901"..., 16384) = 16384
[pid 21114] read(3,  <unfinished ...>
[pid 21113] <... write resumed> )       = 32768
[pid 21114] <... read resumed> "45678901234567890123456789012345"..., 16384) = 16384
[pid 21113] write(4, "01234567890123456789012345678901"..., 32768 <unfinished ...>
[pid 21114] read(3, "01234567890123456789012345678901"..., 16384) = 16384
[pid 21114] read(3,  <unfinished ...>
[pid 21113] <... write resumed> )       = 32768
[pid 21114] <... read resumed> "45678901234567890123456789012345"..., 16384) = 16384
[pid 21113] close(4)                    = 0
[pid 21114] read(3, "01234567890123456789012345678901"..., 16384) = 16384
[pid 21114] read(3, "45678901234567890123456789012345"..., 16384) = 16384
[pid 21114] read(3, "01234567890123456789012345678901"..., 16384) = 16384
[pid 21114] read(3, "45678901234567890123456789012345"..., 16384) = 16384
[pid 21114] read(3, "", 16384)          = 0
[pid 21114] close(3)                    = 0
[pid 21114] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=21114, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
+++ exited with 0 +++

You'll notice that the reads and writes are interleaved and that the writing and reading processes will block a few times as either the pipe is full or not enough data is available for reading.

Gerd Flaig
  • 649
  • 5
  • 6
  • Do these operations occur parallely? – HarshitMadhav Apr 14 '17 at 13:34
  • Read and write operations on pipes can be concurrent, however a read(2) will only return bytes for completed write operations. Given that writes of less than PIPE_BUF bytes are atomic, the reader will only return bytes after the write is done. See pipe(7) for more. – Gerd Flaig Apr 14 '17 at 16:10
  • Can you please explain more clearly? I think this is not what I asked. – HarshitMadhav Apr 14 '17 at 18:25
  • 1
    pipe_read and pipe_write both acquire a mutex on the pipe, so can't run in parallel. See http://lxr.free-electrons.com/source/fs/pipe.c#L250 and http://lxr.free-electrons.com/source/fs/pipe.c#L357. – Gerd Flaig Apr 14 '17 at 20:04
  • Unless you are running a kernel that has CONFIG_PREEMPT=y, the write call can't be preempted until it's either done (in case there's enough buffer space) or blocking (which will force the process to sleep). If you'd like more specific answers, consider updating your question with a time sequence diagram for each scenario with specific event orders. – Gerd Flaig Apr 15 '17 at 14:20
  • I've added a code example with system call trace output for clarification. – Gerd Flaig Apr 15 '17 at 15:04
  • okay so you mean that during the interprocess communication if one process goes to sleep then the communication between them via pipe will stop and will resume when the other process wakes up? – HarshitMadhav Apr 17 '17 at 08:59