Pipes and FIFOs
Overview
This week introduces pipes as a fundamental mechanism for inter-process communication in Unix/Linux systems.
Students will learn about anonymous pipes (unnamed pipes) for communication between related processes, and named pipes (FIFOs) for communication between unrelated processes. We will explore how data flows through pipes, their characteristics, and the system calls used to create and manage them.
By the end of this week, students will understand how to use pipes for process communication, the differences between anonymous and named pipes, and when to use each type.
Key Concepts
What are Pipes?
- Pipes as unidirectional byte streams for IPC
- Producer-consumer model: one process writes, another reads
- Pipes as the foundation of Unix philosophy (“do one thing well”)
- Shell pipes (
|) connecting command outputs to inputs
Pipe Characteristics
- Unidirectional data flow: one-way communication channel
- Byte stream: no message boundaries, continuous stream of bytes
- Buffered I/O: kernel maintains a buffer (typically 64KB on Linux)
- Blocking behavior:
read()blocks if pipe is emptywrite()blocks if pipe buffer is full
- Automatic synchronization: kernel handles coordination between reader and writer
- EOF condition:
read()returns 0 when all write ends are closed
Anonymous Pipes (Unnamed Pipes)
- Created with
pipe()system call - Returns two file descriptors:
fd[0]for reading,fd[1]for writing - Communication between related processes (parent-child via
fork()) - File descriptors inherited by child processes
- Typical workflow:
- Parent creates pipe with
pipe() - Parent forks child process
- Both close unused ends (parent closes read end if writing, etc.)
- Processes communicate via
read()andwrite() - Close all pipe ends when done
- Parent creates pipe with
Named Pipes (FIFOs)
- Created with
mkfifo()system call ormkfifocommand - Exist as special files in the filesystem (
ls -lshowsptype) - Enable communication between unrelated processes
- Persist in the filesystem until explicitly removed
- Opened with standard
open()call - Multiple readers and writers possible (but data interleaving may occur)
- Opening behavior:
open()for reading blocks until a writer opens the FIFOopen()for writing blocks until a reader opens the FIFO- Use
O_NONBLOCKflag to prevent blocking on open
Bidirectional Communication
- Single pipe provides one-way communication
- For bidirectional communication: create two pipes
- Pipe 1: parent → child
- Pipe 2: child → parent
- Each process closes the ends it doesn’t use
Common Patterns and Best Practices
- Always close unused pipe ends to avoid deadlocks and resource leaks
- Check return values of
pipe(),read(),write(), andclose() - Handle
SIGPIPEsignal (sent when writing to a pipe with no readers) - Use
select(),poll(), orepoll()for non-blocking I/O on multiple pipes - Be aware of pipe buffer size limits (use
fcntl()withF_GETPIPE_SZ)
Practice / Lab
Anonymous Pipes: Parent-Child Communication
- Write a program where a parent creates a pipe, forks a child, and sends a message to the child.
- Have the child read from the pipe and print the message.
- Ensure both processes close unused pipe ends.
Bidirectional Communication
- Create two pipes for bidirectional communication between parent and child.
- Parent sends a number to child; child squares it and sends back the result.
Command Pipeline Implementation
- Implement a simplified version of shell piping:
command1 | command2 - Use
pipe(),fork(),dup2(), andexec()to redirect output/input.
Named Pipes (FIFOs)
- Create a FIFO using
mkfifo()in one program. - Write a sender program that opens the FIFO and writes messages.
- Write a receiver program that opens the FIFO and reads messages.
- Run sender and receiver as separate processes and observe communication.
Exploring Pipe Limits
- Write to a pipe without reading to observe blocking behavior when buffer fills.
- Use
ulimit -por/proc/sys/fs/pipe-max-sizeto inspect pipe buffer sizes.
Homework
References & Resources
Required
- Pipes in C programming
- Unix Pipes Explained
- Named Pipes (FIFOs) in Linux
- Pipe, Fork and Exec
- Pipes in Linux (GeeksforGeeks)
- Kerrisk, The Linux Programming Interface
- Chapter 44: Pipes and FIFOs
- Advanced Programming in the UNIX Environment — W. Richard Stevens, Chapter 15 “Interprocess Communication”
Recommended
- Linux manual page - pipe(2)
- Linux manual page - mkfifo(3)
- Linux manual page - fifo(7)
- Linux manual page - dup2(2)
- Understanding Pipes in Unix
- Named Pipes (IBM Developer)
- Pipe Implementation in Linux Kernel
- How Unix Pipes Are Implemented (LWN.net)
Quiz (Self-check)
- What is the difference between anonymous pipes and named pipes (FIFOs)?
- Why must unused pipe ends be closed in both parent and child processes?
- What happens when you try to write to a pipe that has no readers?
- How does
pipe()communicate the file descriptors to the caller? - What is the typical size of a pipe buffer in Linux?
- How can you implement bidirectional communication using pipes?
- When would you use a FIFO instead of an anonymous pipe?
- What does
read()return when all write ends of a pipe are closed? - What flag can you use to prevent
open()from blocking when opening a FIFO? - How do shell pipelines like
ls | grep txt | wc -lwork internally?
Suggested Tools
mkfifo— create named pipes from the command linels -l— identify FIFOs (shown as typep)cat— read from or write to FIFOs for testingstrace— tracepipe(),read(),write()system callslsof— list open file descriptors including pipespv— pipe viewer for monitoring data flow through pipestee— read from stdin and write to both stdout and files