 | Interprocess communication concepts
 | Different processes do not share address space -- they need interprocess
communication to talk to one another. |
 | This is not network programming, where processes running on different
machines talk to each other via network. Here all the processes involved are
running on the same machine. |
 | The processes having parent-child relation can communicate with global
variables. After the termination of the child the parent can receive values
from the children by their exit code. |
 | In this lecture we will consider pipe and FIFO, which are part of POSIX,
and are supported by many UNIX implementation. |
|
 | Pipe
 | Pipe is a half-duplex communication channel between processes that have
parent-child relation. |
 | The pipe interface opens a pipe for
reading at one end, and writing at the other. |
 | It is easy to see that other than parent-child related processes, others
could not know the file descriptors, and cannot use them as a result. |
 | After creating a pipe a process usually creates another copy by fork, so
that they share the pipe. Usually the parent and the child will decide
whether to read from or write to the pipe, and will close the other end that
they do not need. |
 | See the figure on page 430 for an illustration. |
 | There could be all kinds of problem accessing a pipe.
 | Read from a closed pipe.
 | The read returns 0, just like an EOF. |
|
 | Write to a closed pipe.
 | A SIGPIPE is generated. |
|
|
 | Now try the program on page 431.
 | The parent writes and the child reads. |
|
 | Now consider a program that pipes the output to a pager (on page 432).
 | The default pager is "more". |
 | The parent does the following:
 | The parent creates a pipe and share it with the child. |
 | Then the parent reads from a file, and writes to the pipe. The
parent repeats this process until it reads all the data from the input
file. |
 | Then the parent waits for the child to complete. |
|
 | The child does the following:
 | The child direct its standard input to the input end of the pipe
(with dup). |
 | Then the child determines the pager -- it is either from the
environment or from the default value. |
 | Then the child exec the pager. Since the standard input has been
redirected to the pipe. The pager will read from the pipe. |
|
|
 | Now we use pipe to synchronize parent and child (the code is on page
434).
 | The code has three major groups of functions.
 | TELL_WAIT
 | The subroutine creates two pipes -- one for letting the parent
wait for the child, and one for the other way around |
|
 | TELL_PARENT and TELL_CHILD
 | These routines tell the other by writing a string into the
pipe. |
|
 | WAIT_PARENT and WAIT_CHILD
 | These routines try to read from the pipe. If the data is not
there, they will block -- just as we want them to. |
|
|
|
 | popen and
pclose interface
 | The popen interface integrates the following into a single function.
 | Create a pipe. |
 | Fork a child process. |
 | Make the child process exec a command. |
|
 | The arguments to popen.
 | A command string
 | What do you want the child to do? |
|
 | A "direction string"
 | The parent should read from ("r") or write to ("w") the pipe. |
|
|
 | The same pager program is implemented with popen in a simpler way on
page 436. |
 | The implementation of popen on page 438-439.
 | The implementation uses an array of process ids to record those
process ids that are associated with a particular pipe file descriptor.
The pipe file descriptor is used to index this array. See below. |
 | The parent does the following.
 | Creates a pipe. |
 | Forks a child process. |
 | Use fdopen to convert the file
descriptors (int) returned by pipe into standard I/O style file
pointer (FILE*). |
 | The file pointer is returned. |
|
 | The child does the following.
 | Depending on the direction string, redirects the standard input
(output) to the reading (writing) end of the pipe. |
 | Executes the command string. |
|
 | The pclose does the following.
 | Uses fileno to convert a file
pointer back to a file descriptor. |
 | Uses the file descriptor as an index to access the child process
id stored during popen. |
 | Uses waitpid to wait until the child
ends. |
 | Returns the status code from the child. |
|
|
 | We can use popen to filter the input we want to send into an
application.
 | First check out the filter program on page 440, which reads in
characters and convert them into lower case. |
 | The program flushes the output when it sees a newline, and
terminates when the input is EOF. |
 | The main program uses popen to create a process and make it run the
filter program. |
 | Then the main program writes the prompt. |
 | The child filter process reads from the stdin and convert it into
lower case. |
 | The child filter process then writes the output into the pipe, which
will be read by the parent. |
|
|
|
 | Coprocess
 | A filter reads from stdin, and writes to stdout. |
 | A coprocess is a process that reads and writes data to another process. |
 | See the picture on page 441 for an example. |
 | Program 14.8 is a filter that reads two data from stdin, adds them
together, and writes the result to stdout. We compile it and name it add2. |
 | Now we write another program that creates a coprocess running add2.
 | First the program installs a signal handler for SIGPIPE, which will be
generated if there is something wrong with the pipe, |
 | Then the program creates two pipes and forks a child process.
 | The parent does the following:
 | Closes those fds it does not need. |
 | Reads two numbers from stdin, and writes to the first pipe. |
 | Reads from the second pipe, which should have the sum of the two
numbers written in to the first pipe. |
 | Writes the result to stdout. |
|
 | The child does the following:
 | Closes those fds it does not need. |
 | Redirects the stdin to the input end of the pipe, and stdout to
the output end of the pipe, |
 | exec add2. |
|
|
|
|
 | FIFO
 | A FIFO is a named pipe, that is, a pipe with a name in the file system. |
 | FIFO is a special kind of file. In fact it is simply a place where
different processes (not necessarily have parent-child relation) can
communicate. |
 | A FIFO is created by mkfifo system call, which is quite similar to open. |
 | When accessing a FIFO, implicit synchronization is in effects.
 | The reading process will block in the open call until some other
process open it for writing. |
 | If O_NONBLOCK is specified, the open for reading returns immediately,
but the open for write-only will have runtime error. |
 | A writing process will have SIGPIPE if no one open the FIFO for
reading. |
|
 | FIFO usage
 | Passing data between one shell command to another.
 | See the example on page 446. |
 | A FIFO fifo1 is created just to route data. |
 | A command tee is used to duplicate data into two direction. |
|
 | Client-server communication
 | Two processes can communicate via a well-known FIFO. |
 | Figure 14.12 shows that different clients can send messages to the
same server, however, the server will not be able to reply since we
cannot be sure that the correct client will read the correct message. |
 | The solution is in Figure 14.13, where each client has its own FIFO
to which the server can send reply. |
|
|
|