Pipes and FIFOs are efficient ways to do file-like input and output between processes. Their biggest benefit is the ability to treat the endpoints as formatted input and output streams, just like you would read and write from files, or from streams like standard input and output.
In this studio, you will:
pipe()
system call
mkfifo()
function
Please complete the required exercises below, as well as any optional enrichment exercises that you wish to complete.
As you work through these exercises, please record your answers, and when finished email your results to dferry@email.wustl.edu with the phrase Linux Pipes in the subject line.
Make sure that the name of each person who worked on these exercises is listed in the first answer, and make sure you number each of your responses so it is easy to match your responses with each exercise.
pipe()
system call to create a
communicating child and parent. However, once created, pipes cannot be shared
between executing processes. Thus, the standard way to use this system call is
to call the pipe()
function, which will create separate pipe
endpoints for reading and writing, and then to fork()
the process.
Thus, the child will inherit the pipe endpoints from the parent, and both
processes now have access.
Create a program which:
pipe()
to create a pipe with read and write file descriptors (see
man 2 pipe
for details)
fork()
to create a child process
close()
, and the parent process closes its copy of the write
file descriptor similarly
Pipe I/O, like file I/O in C, is comparatively low level. There are two
approaches you can use to read and write to your pipe. You could use
the integer file descriptors returned by pipe()
directly with the read()
and write()
system calls, documented at man 2 read
and man 2 write
. However you might find it easier to instantiate
a FILE*
stream, which allows you to work with your pipe like it
was any other file object (i.e. you write to the pipe with fprintf()
and read from the pipe with intelligent input operations such as fgets()
or fscanf()
. You can open a file stream from a file descriptor
with the fdopen()
function.
Read more about the difference
between file descriptors and file streams here. Of course, all of the above
functions have informative man pages.
Hint: Blocking functions that read the pipe will block indefinitely until
they are able to return successfully or the write-end of the pipe is closed by
the writer. The writer should write all of it's data and then call
close()
on its file descriptor when it is done. This allows you to
write code such as while( fgets() != NULL )
to do open-ended reads,
on the pipe, which will eventually fail and return once the write-end is closed.
PIPE_BUF
sized data).
To begin, create a new file for your active object. This program should:
mkfifo()
. This is documented
at man 3 mkfifo
. Be careful not to confuse it with the program
called mkfifo
that is documented at man 1 mkfifo
.
fopen()
.
while
loop that continually attempts to read from the
FIFO. The same code you used to read from a pipe previously can be adapted
here. Whenever something is read, print it to the standard output.
When you run your program it will create a FIFO which will appear in the
filesystem. In a separate terminal, write some data into the FIFO and validate
that it is read by your program correctly. For example, if your FIFO is named
my_ao_fifo
, the command "echo "my_message" > my_ao_fifo
will insert "my_message" into the FIFO. Test your program with larger input
as well, for example: "cat my_file.c > my_ao_fifo
".
As the answer to this exercise, copy and paste the terminal output.
fopen( fifo_name, "w" )
. Your active object will not ever
write to this stream, but the fact that it is held open will prevent your
program from automatically quitting.
Next, modify the active object to read from the FIFO with the function
fscanf()
. This allows you to perform formatted input. Your program
should read integer inputs from the pipe, double the input, and then print out the
original and the new values. Your input stream should not have any non-integer characters
and you do not need to handle this case.
Test your program by passing integers into your FIFO, and copy and paste the results here.
fopen(fifo_name, "w")
and
insert integer values with fprintf()
. One of these programs should only insert even numbers,
and the other should only insert odd numbers. Run these programs
long enough to verify that they can both write concurrently to the FIFO without
problem. Examine the output of your active object to verify correctness.