Loading content...
Every IPC mechanism has strengths and limitations. Understanding FIFO constraints helps you choose the right tool for each situation. FIFOs excel at simple, unidirectional byte streams between local processes, but they have fundamental limitations that make other mechanisms preferable in certain scenarios.
This page examines these limitations honestly, helping you make informed architectural decisions.
By the end of this page, you will understand:
• Fundamental architectural limitations of FIFOs • Performance and scalability constraints • Platform-specific considerations • When to choose alternative IPC mechanisms • How to work around common FIFO limitations
FIFOs provide one-way communication only. Data flows from writers to readers, never the reverse on the same FIFO. This fundamental constraint shapes how FIFO-based systems are designed.
Implications:
| Mechanism | Bidirectional Support | Complexity |
|---|---|---|
| FIFO | Requires 2 FIFOs | Medium—manage two paths, two fds |
| Unix Socket (SOCK_STREAM) | Single socket, full-duplex | Low—one path, standard API |
| Unix Socket (SOCK_DGRAM) | Single socket per endpoint | Low—simple send/recv |
| Shared Memory + Semaphores | Inherently bidirectional | High—manual synchronization |
| Message Queues | Separate queues per direction | Medium—similar to FIFOs |
Sometimes one-way communication is exactly what you need:
• Logging systems: Writers send logs, logger reads—no response needed • Event buses: Publishers emit events, subscribers consume • Command queues: Controller sends commands, worker executes
For these patterns, FIFO's simplicity is a feature, not a bug.
FIFOs exist in the local filesystem and cannot communicate across network boundaries. Unlike sockets, FIFOs have no network transport capability.
Network Limitation Details:
Unix domain sockets combine FIFO-like local efficiency with socket API familiarity:
• Local-only like FIFOs (no network overhead)
• Bidirectional like TCP sockets
• Socket API (connect, send, recv)
• Can be upgraded to TCP for network support
For new projects needing local IPC with future network potential, prefer Unix sockets.
FIFOs provide a byte stream—there's no concept of discrete messages. A write() of 100 bytes might be read as one 100-byte read(), two 50-byte reads, or any other combination.
Stream vs Message Semantics:
| Characteristic | FIFO (Byte Stream) | Message Queue |
|---|---|---|
| Read granularity | Any number of bytes | One complete message |
| Message boundaries | Not preserved | Preserved automatically |
| Partial reads | Common and expected | Not possible (all or nothing) |
| Application framing | Required | Not needed |
| Multiple message types | Application must demux | Built-in type field |
Application-Level Framing Required:
To send discrete messages over FIFOs, you must implement framing:
123456789101112131415161718
// Pattern 1: Fixed-size messagestypedef struct { uint32_t type; char payload[252]; // Fixed 256-byte total} FixedMessage; // Pattern 2: Length-prefixed messagesvoid send_message(int fd, const char *msg, size_t len) { uint32_t net_len = htonl(len); write(fd, &net_len, sizeof(net_len)); // Length first write(fd, msg, len); // Then payload} // Pattern 3: Delimiter-separated (text protocols)void send_line(int fd, const char *line) { write(fd, line, strlen(line)); write(fd, "\n", 1); // Newline delimiter}With byte streams, you must also handle:
• Partial writes: write() may write fewer bytes than requested
• Partial reads: read() may return fewer bytes than requested
• Message reassembly: Buffer incoming data until complete message received
This boilerplate is eliminated by using message queues or datagram sockets.
FIFO kernel buffers are limited in size (typically 64KB on Linux). This creates back-pressure when writers produce faster than readers consume.
Buffer Size Details:
| Platform | Default FIFO Buffer | Configurable? |
|---|---|---|
| Linux | 64 KB (16 pages) | Yes, via fcntl(F_SETPIPE_SZ) up to /proc/sys/fs/pipe-max-size |
| macOS | 16 KB | No |
| FreeBSD | 16 KB | Limited |
Implications of Limited Buffers:
123456789101112131415
#include <fcntl.h>#include <stdio.h> int increase_fifo_buffer(int fd, int new_size) { // Linux-specific: increase FIFO buffer size int result = fcntl(fd, F_SETPIPE_SZ, new_size); if (result < 0) { perror("F_SETPIPE_SZ"); return -1; } // Actual size may differ (rounded to page size) int actual = fcntl(fd, F_GETPIPE_SZ); printf("Requested: %d, Actual: %d bytes\n", new_size, actual); return actual;}Data in a FIFO exists only in kernel memory. When all readers disconnect or the system reboots, unread data is lost.
Persistence Implications:
When Persistence Matters:
For durable messaging, consider:
• POSIX Message Queues: Persist until explicitly removed (though not across reboots) • SQLite: Embedded database for persistent queues • Redis: In-memory with optional persistence • RabbitMQ/Kafka: Enterprise message brokers with guaranteed delivery
While multiple readers can open a FIFO, each byte can only be read by one reader. FIFOs don't support publish-subscribe or multicast patterns.
Multiple Reader Behavior:
read() first| Pattern | FIFO Support | Better Alternative |
|---|---|---|
| Single consumer | ✓ Perfect fit | — |
| Competing consumers (work queue) | Partial—no fair distribution | Message queue with round-robin |
| Pub-sub (all receive) | ✗ Not supported | Unix multicast sockets, message brokers |
| Fan-out (one-to-many) | ✗ Not supported | Multiple FIFOs, shared memory |
FIFOs require a filesystem that supports special files. This creates constraints in certain environments:
Filesystem Compatibility:
Linux Unix sockets support an "abstract namespace" that doesn't touch the filesystem:
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
addr.sun_path[0] = '\0'; // Abstract namespace
strcpy(&addr.sun_path[1], "my_socket");
This avoids filesystem dependencies entirely—useful in containers and restricted environments.
You now understand FIFO limitations and can make informed decisions about when to use them. Next, we'll explore practical use cases where FIFOs excel, seeing these mechanisms applied to real-world problems.