Monday, November 10, 2014

Unix Prog: IPC Pipe(1)

1. Pipes
In history, pipes have been half duplex: data flows in only one direction. Some systems now support full duplex. Pipes can be used only between processes that have a common ancestor.

A main area for pipe: every time we type a sequence of commands in a pipeline for the shell to execute, the shell creates a separate process for each command and links the standard output of one to the standard input of the next using a pipe.

2. Pipe system call:
System Definition:
 ubuntu@ip-172-31-23-227:~$ less /usr/include/unistd.h  
 ......  
 /* Create a one-way communication channel (pipe).  
   If successful, two file descriptors are stored in PIPEDES;  
   bytes written on PIPEDES[1] can be read from PIPEDES[0].  
   Returns 0 if successful, -1 if not. */  
 extern int pipe (int __pipedes[2]) __THROW __wur;  
 ......  

two file descriptors are returned, pipedes[0] is open for reading, pipedes[1] is open for writing.

For a pipe from the parent to the child, the parent closes the read end of the pipe(fd[0]), and the child closes the write end(fd[1]). For a pipe from the child to the parent, the parent closes fd[1] and child closes fd[0].

Following diagram illustrates this:

If we read from a pipe whose write end has been closed, read returns 0 to indicate an end of file after all the data has been read. If we write to a pipe whose read end has been closed, the signal SIGPIPE is geerated. write returns -1 with errno set to EPIPE.

The constant PIPE_BUF specifies the kernel's pipe buffer size:
 ubuntu@ip-172-31-23-227:~$ less /usr/include/linux/limits.h  
 ......  
 #define PIPE_BUF    4096  /* # bytes in atomic write to a pipe */  
 ......  
When we're writing to a pipe(or FIFO), a write of PIPE_BUF bytes or less will not be interleaved with the writes from other processes to the same pipe(or FIFO). If multiple processes are writing to a pipe(or FIFO), and if we write more than PIPE_BUF bytes, the data might be interleaved with the data from other writers.

3. Example of pipe:
pipe.c:
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<unistd.h>  
   
 int main(int argc, char* argv[])  
 {  
  int n;  
  int fd[2];  
  pid_t pid;  
  char line[20];  
   
  // Build the pipe  
  if(pipe(fd) < 0) {  
   printf("pipe error!\n");  
   exit(1);  
  }  
   
  // Make the child process  
  if((pid = fork()) < 0) {  
   printf("fork error!\n");  
   exit(2);  
  } else if(pid > 0) { // parent  
   sleep(2);  
   close(fd[0]);  
   write(fd[1], "hello world!\n", 12);  
  } else {  
   close(fd[1]);  
   n = read(fd[0], line, 20);  
   printf("return size: %d\n", n);  
   write(STDOUT_FILENO, line, n);  
  }  
   
  exit(0);  
 }  

shell:
Note: Even if parent sleep for 2 seconds before closing read end and write to write end. The child process just get stuck in read system call to wait for the writing of parent process.So we can assume that file descriptors returned by pipe are blocking I/O.

 ubuntu@ip-172-31-23-227:~$ ./pipe.out  
 ubuntu@ip-172-31-23-227:~$ return size: 12  
 hello world!  

No comments:

Post a Comment