FIFOs
FIFOs, also called named pipes, are used for one-way communication between two processes. Data written into a FIFO can later be read from the FIFO in the same order that it was written–First In, First Out. The kernel implements each FIFO as a fixed-size circular buffer in memory, so access to a FIFO is usually very fast, though with a limited capacity. Writing too much data to a FIFO without reading an equal amount can fill up the FIFO and cause subsequent write operations to block or fail until space is available–FIFOs are meant to be used by two processes that are actively communicating, with one consuming data as soon as it is written by the other!
A process can create a named fifo using the mkfifo()
system call, which takes a file path and access mode argument, similar to open()
, except that it doesn’t actually open the fifo after creation. The newly created FIFO will persist in the filesystem just like any other file. Once a FIFO has been created, any process with the appropriate credentials can open it for reading and writing. Since FIFOs are meant to be used by two processes that are actively communicating, opening a FIFO for reading or writing blocks until another process opens the same FIFO with the complementary access mode. This ensures that there is an active read-write connection between two processes before either attempts to access the FIFO.
Multiple processes can read and write to the same FIFO, without restriction, though this is likely to result in conflicts and data corruption without additional mechanisms to serialize reads and writes by different processes. Additionally, when processes communicate bidirectionally using multiple FIFOs, programmers must be very careful to avoid deadlocks! In general, FIFOs are best used for simple one-way communication between two processes.
Pipes
POSIX has an almost identical concept to FIFOs called pipes, and as stated earlier, FIFOs are often called named pipes. In fact, pipes and FIFOs actually are identical, except for how they are created and how processes acquire open file descriptors to read to and write from them.
As described above, FIFOs are created with the mkfifo()
system call, which creates a FIFO file in the file system associated with a new unidirectional pipe. To acquire open file descriptors, processes then open this FIFO file, including the process that created the FIFO.
In contrast, unnamed, or anonymous, pipes can be created via the pipe()
system call, which creates a new pipe and returns to the caller two file descriptor numbers associated with the read and write sides of the pipe. Unrelated processes can’t easily acquire an open end of one of these pipes. However, two distinct processes can acquire opposite pipe ends through direct inheritance. When a process forks, its child inherits copies of its open file descriptors, including open pipe ends, which can then be used for communication with the parent, or another process that similarly inherited the open ends of the same pipe.
This is how the shell manages command pipelines. When executing the first command, it creates a new pipe, and redirects standard output of the first command to the input side of the pipe. Then when it executes the second command, it redirects its standard input to the output side of the pipe. Both commands inherit these open file descriptors directly from the shell.