🔗Go deeper — read the bookIPC: pipes & fork— runnable code & full walkthrough →

ipc · medium

IPC: Pipes & FIFOs — Unidirectional Byte Streams Between Processes

POSIX pipes are kernel-managed unidirectional byte streams. pipe() returns two fds: fd[0] (read end) and fd[1] (write end). After fork(), both parent and child inherit both ends; each closes the unused end. write() into fd[1] copies bytes into the kernel buffer (~65KB); read() from fd[0] drains them. Both operations block if the buffer is full or empty respectively — this provides built-in flow control. Closing the write end sends EOF to the reader (read() returns 0). Anonymous pipes are visible only to related processes. Named FIFOs (mkfifo) create a filesystem entry visible to any process on the same host; open() on a FIFO blocks until both ends connect. Shell | (pipe operator) creates an anonymous pipe between adjacent processes in the pipeline.

🔑 Key line

pipe(): fd[0]=read, fd[1]=write — unidirectional byte stream; always close unused end after fork; write blocks when full, read blocks when empty; close(write end) sends EOF; named FIFO (mkfifo) extends this to unrelated processes via a filesystem path.

The code

// Anonymous pipe: parent → child byte stream
int fd[2];
pipe(fd); // fd[0]=read end, fd[1]=write end
pid_t child = fork();
if (child == 0) {
close(fd[1]); // child doesn't write
char buf[256];
ssize_t n = read(fd[0], buf, sizeof(buf));
buf[n] = '\0';
printf("Child got: %s\n", buf);
close(fd[0]);
} else {
close(fd[0]); // parent doesn't read
const char* msg = "Hello from parent";
write(fd[1], msg, strlen(msg));
close(fd[1]); // EOF → child's read() returns 0
wait(nullptr);
}
// Named FIFO — any two unrelated processes
mkfifo("/tmp/my.fifo", 0644);
// Writer (one process): open O_WRONLY, write, close
// Reader (other process): open O_RDONLY, read, close
// Both open() block until the other end connects!
// unlink() removes the FIFO from the filesystem.
// Shell pipe is a kernel anonymous pipe:
// ls -la | grep .cpp
// stdout of ls → pipe → stdin of grep

What this lesson walks through

  1. 01Pipe fundamentals — unidirectional kernel byte stream
  2. 02fork() — child inherits both pipe ends
  3. 03Parent writes — bytes flow into kernel buffer
  4. 04Parent closes write end — child reads EOF
  5. 05Pipe full — writer blocks
  6. 06Named FIFO vs anonymous pipe — when to use which

pipe(fd) creates two file descriptors: fd[0] (read end) and fd[1] (write end). Data flows one way only: write to fd[1], read from fd[0]. The kernel maintains an in-memory ring buffer (~65KB). Pipes are anonymous — only visible via inherited file descriptors after fork().

See it animated — step by step, at your own pace

Unlock the full interactive walkthrough of IPC: Pipes & FIFOs — Unidirectional Byte Streams Between Processes and 100+ animated C++ interview lessons.

← Previous
Process Memory Layout
Next →
IPC: Shared Memory — Zero-Copy Direct Memory Access Between Processes