Pipes and Named Pipes

54
0

Introduction

Pipes and named pipes are Inter-Process Communication mechanisms used for simple byte-stream communication. They let one process write data while another process reads that data through an operating-system-managed channel.

This idea is common in shell pipelines. In a command like ls | grep ".txt", one process produces output and another process consumes it as input.

What Is a Pipe?

A pipe is a kernel-managed byte buffer with two ends: one end for reading and one end for writing. The writer sends bytes into the pipe, and the reader consumes those bytes from the pipe.

The usual descriptor view is:

  • fd[0]: Read end of the pipe.

  • fd[1]: Write end of the pipe.

A pipe is a byte stream. It does not preserve high-level message structure by itself, so the reader receives bytes in the order they were written.

Why Pipes Are Needed

Processes have separate address spaces, so one process cannot simply write into another process's memory. A pipe gives them a controlled IPC path without breaking process isolation.

For example, ls normally writes output to the terminal. If we want grep ".txt" to filter that output, the output of ls must become the input of grep.

A pipe solves this by connecting the standard output of one process to the standard input of another process.

Pipes and its Need

Pipes and its Need

Pipe Flow with fork

Anonymous pipes are commonly used between related processes. A parent creates the pipe first, then calls fork, so the child inherits the pipe file descriptors.

A compact shape is:

int fd[2];
pipe(fd);
pid_t pid = fork();
if (pid == 0) {
// Child: reads from the pipe
close(fd[1]);
read(fd[0], buffer, sizeof(buffer));
}
else if (pid > 0) {
// Parent: writes to the pipe
close(fd[0]);
write(fd[1], message, strlen(message));
}
else {
// fork() failed
handle_fork_failure();
}

After fork, the parent and child are separate processes, but their inherited descriptors can refer to the same kernel pipe. One side writes using fd[1], and the other reads using fd[0].

Why Unused Ends Must Be Closed

Closing unused pipe ends is important because it affects blocking and EOF behavior.

If the reader keeps a write end open, or some other process still has a write end open, the reader may not see EOF. The kernel may assume that more data can still arrive.

The basic behavior is:

  • Pipe empty but write end open: A read may block because data may arrive later.

  • Pipe buffer full: A write may block until the reader consumes data.

  • All write ends closed: The reader can detect EOF after buffered data is consumed.

So in a simple parent-writer and child-reader setup, the writer closes the read end, and the reader closes the write end.

Shell Pipeline Example

For a pipeline such as ls | grep ".txt" the shell creates the pipe before forking the command processes. Then it connects the commands using file descriptor redirection.

The basic flow is:

  • Shell creates a pipe: It gets a read end and a write end.

  • Shell forks the ls child: ls uses the pipe write end as standard output.

  • Shell forks the grep child: grep uses the pipe read end as standard input.

  • Unused ends are closed: Each process closes the ends it does not need.

  • Data flows: ls writes directory output, and grep reads and filters it.

  • EOF arrives: When all write ends close, grep can finish.

This is why the pipe must be created before the child processes are forked. The children need to inherit descriptors connected to the same kernel pipe object.

Shell Pipeline

Shell Pipeline

Named Pipe or FIFO

A named pipe, also called a FIFO, gives pipe-like behavior through a name in the filesystem. It is still an IPC object, but processes can open it by path. For example: mkfifo mypipe

After this, one process can open mypipe for writing, and another process can open it for reading. The processes do not need to have a parent-child relationship.

The filesystem name identifies the FIFO. The bytes are not stored like ordinary file contents in that path; they pass through a kernel-managed pipe buffer and are consumed when read.

Named Pipe or FIFO

Named Pipe or FIFO

Anonymous Pipe vs Named Pipe

Point

Anonymous Pipe

Named Pipe / FIFO

Name

No filesystem name

Has a filesystem path

Common use

Related processes through inheritance

Related or unrelated local processes

Access method

Inherited file descriptors

Opened by path

Data style

Byte stream

Byte stream

Anonymous pipes are natural for shell pipelines and parent-child communication. Named pipes are useful when independently started processes need a common local IPC endpoint.

When Pipes Fit Well

Pipes are a good choice when communication is simple and stream-based. They work especially well for local process composition. Good fits include:

  • Simple byte stream: One process writes bytes, another reads them.

  • One-way flow: Data naturally moves from producer to consumer.

  • Shell-style composition: One command's output becomes another command's input.

  • Local IPC: Communication happens on the same machine.

Pipes are not the best choice when the system needs structured messages, many clients, persistent stored data, or network communication. In those cases, message queues, sockets, shared memory, or another IPC mechanism may fit better.

Summary

Pipes are IPC mechanisms for local byte-stream communication. An anonymous pipe has a read end and write end, usually accessed through inherited file descriptors such as fd[0] and fd[1].

A named pipe, or FIFO, provides similar stream behavior through a filesystem name, so unrelated processes can open the same IPC object. Pipes fit simple one-way byte streams and shell pipelines, but they are not ideal for structured messages, many clients, or network communication.

CS Core

Read Similar Blogs

Comments0