Skip to content
Part IA Lent Term

Pipes and Named Pipes (FIFOs)

UNIX pipe data flow: Process A writes to the kernel pipe buffer; Process B reads from it, with the circular buffer providing flow-control back-pressure

Anonymous pipes

An anonymous pipe (pipe() system call) creates a unidirectional byte stream between a pair of file descriptors:

int pipefd[2];
pipe(pipefd);  // pipefd[0] = read end, pipefd[1] = write end

Data written to pipefd[1] can be read from pipefd[0]. The pipe is a kernel buffer, typically 64 KB on Linux. Writes of up to PIPE_BUF bytes (4096 on Linux) are atomic — they will not be interleaved with writes from other processes. Larger writes may be interleaved.

Pipes are only usable between related processes (parent-child, or siblings sharing the parent’s descriptors). The typical pattern:

  1. Parent calls pipe().
  2. Parent calls fork(). The child inherits a copy of both descriptors.
  3. Parent closes the read end; child closes the write end (or vice versa).
  4. Parent writes; child reads (or child writes; parent reads).

The shell’s pipe operator

ls | grep foo translates to:

pipe(pipefd);
if (fork() == 0) {
    close(pipefd[0]);          // close read end
    dup2(pipefd[1], STDOUT_FILENO);  // redirect stdout to pipe write end
    close(pipefd[1]);
    execlp("ls", "ls", NULL);
}
// Parent
close(pipefd[1]);              // close write end
dup2(pipefd[0], STDIN_FILENO); // redirect stdin to pipe read end
close(pipefd[0]);
execlp("grep", "grep", "foo", NULL);

The dup2() calls redirect the standard streams to the pipe, so the programmes can use printf() / scanf() without knowing they are communicating through a pipe.

Named pipes (FIFOs)

A named pipe (or FIFO) is created with mkfifo() or the mkfifo command. It appears as a special file in the file system:

mkfifo /tmp/myfifo
ls -l /tmp/myfifo   # shows type 'p' (pipe)

A named pipe behaves like a pipe, but any process (not just related ones) can open it by name. One process opens the FIFO for writing, another for reading; the kernel connects them. Unlike regular files, the data never touches the disk — it is buffered in the kernel’s pipe buffer, just like an anonymous pipe.

Named pipes support rendezvous semantics: an open() for reading blocks until another process opens the same FIFO for writing (and vice versa), unless O_NONBLOCK is specified.

Pipes vs named pipes vs signals

FeatureSignalsPipesNamed pipes
Data transferNo (signal number only)Yes — byte streamYes — byte stream
SynchronisationAsynchronous; hard to synchronise onBuilt-in: read blocks until data, write blocks when fullSame as pipes
Process relationshipAny (by PID)Related only (inherited descriptors)Any (by path name)
ScopeSame UID (usually)Fork treeAny process with FS access
PersistenceEphemeral (delivered or merged)Lifetime of processes holding descriptorsPersistent in FS; survives process lifetime
CapacityMinimal (merged, no queue)Kernel buffer (64 KB)Kernel buffer (64 KB)

Summary

  • Pipes are unidirectional byte streams between related processes; created with pipe() and inherited across fork().
  • The shell uses pipes + dup2() to connect commands’ stdin/stdout.
  • Named pipes (FIFOs) extend pipes to unrelated processes by existing in the file system.
  • Unlike files, pipe data is buffered in memory, not on disk.
  • Signals are for notification; pipes and FIFOs are for data.