Pipes and FIFOs
Unix pipes as unidirectional byte streams — anonymous pipes for related processes and named pipes (FIFOs) for unrelated ones.
A pipe is a unidirectional byte stream: one process writes into it, another reads out. It
is the oldest form of Unix IPC and the mechanism behind the shell's | operator. This week
covers both anonymous pipes (between related processes) and named pipes / FIFOs
(between any processes).
What is a pipe?
Pipes embody the Unix philosophy — small programs composed through text streams. Key properties:
- Unidirectional — data flows one way; for two-way communication you use two pipes.
- Byte stream — no message boundaries, just a continuous stream of bytes.
- Buffered — the kernel holds the data (typically 64 KiB on Linux).
- Self-synchronizing —
readblocks when the pipe is empty;writeblocks when the buffer is full. - EOF —
readreturns0once all write ends are closed.
The shell wires pipes for you: in ls | grep txt | wc -l, each | connects one command's
stdout to the next command's stdin.
Anonymous pipes
Created with pipe(fd), which fills a two-element array: fd[0] is the read end and
fd[1] is the write end. Because file descriptors are inherited across fork, this
connects a parent and child:
int fd[2];
pipe(fd);
if (fork() == 0) { // child: reads
close(fd[1]); // close unused write end
char buf[64];
ssize_t n = read(fd[0], buf, sizeof buf);
write(STDOUT_FILENO, buf, n);
close(fd[0]);
} else { // parent: writes
close(fd[0]); // close unused read end
write(fd[1], "hello", 5);
close(fd[1]); // reader now sees EOF
}Always close unused ends
Each process must close the pipe end it doesn't use. If a write end stays open somewhere, the reader never sees EOF and blocks forever; leaked descriptors also waste resources.
Combining pipe + fork + dup2 + exec is exactly how a shell implements
command1 | command2 — redirect command1's stdout into the pipe and command2's stdin out
of it.
Named pipes (FIFOs)
A FIFO is a pipe with a name in the filesystem, created by mkfifo(path, mode) (or the
mkfifo shell command). It shows up in ls -l with type p, and it lets unrelated
processes talk — any process that can open the path can use it:
mkfifo /tmp/chan
cat < /tmp/chan # reader (blocks until a writer opens it)
echo "hi" > /tmp/chan # writer, from another terminalOpening a FIFO blocks until the other end is also opened, unless you pass O_NONBLOCK.
The data still lives in kernel memory; only the name persists on disk.
Practice / lab
- Send a message parent → child through an anonymous pipe, closing unused ends on both sides.
- Use two pipes for bidirectional communication: parent sends a number, child squares it and sends it back.
- Reimplement
command1 | command2withpipe,fork,dup2, andexec. - Create a FIFO with
mkfifoand exchange messages between two separate programs.
Homework
- IPC-2: Prime Calculator — pass a number to a child over an anonymous pipe and read the result back.
References & resources
Required
- Pipes in Linux —
pipe()(GeeksforGeeks) - Pipe, fork and exec (video)
- The Linux Programming Interface (Kerrisk) — Ch. 44: Pipes and FIFOs
Optional / enrichment
pipe(2)·mkfifo(3)·fifo(7)- Understanding pipes in Unix (Baeldung)
- How Unix pipes are implemented (LWN)
Self-check
- What is the difference between an anonymous pipe and a FIFO?
- Why must both processes close the pipe ends they don't use?
- What happens when you write to a pipe with no readers?
- What does
readreturn once all write ends are closed? - How do you achieve bidirectional communication with pipes?