Pipes

A pipe is a unidirectional kernel buffer connecting two file descriptors — one write end and one read end. Created with pipe(int pipefd[2]). Both ends are regular file descriptors: they respect the three-table FD model, are inherited across fork(), and are closed with close().

The canonical pattern

int pipefd[2];
pipe(pipefd);
pid_t pid = fork();
if (pid == 0) {
    close(pipefd[1]);   // child doesn't write
    // read from pipefd[0]...
    _exit(0);
}
close(pipefd[0]);       // parent doesn't read
// write to pipefd[1]...

The most common pipe bug: forgetting to close the unused end. If the parent keeps pipefd[0] open, the child’s read() will never return EOF — the kernel sees a writer still alive.

Key properties

  • Kernel-buffered (typically 64 KiB on Linux)
  • read() blocks until data is available or all write ends are closed
  • write() to a pipe with no readers delivers SIGPIPE; use signal(SIGPIPE, SIG_IGN) or MSG_NOSIGNAL/O_NONBLOCK for servers

In the curriculum

Covered in m07-processes-signals lesson 7-3 (“Pipes and IPC”). The Minimal Shell project (7-proj) uses pipes for command pipelines. Also relevant to m08-sockets-networking — sockets are generalised pipes over a network.

See also

file-descriptors, fork, signals