Using FIFOs (named pipes) is a convenient way to communicate with other processes. A FIFO can be used in similar ways as an ordinary file. You can open, write, read, and close it. However, they are not the same. These are a couple of caveats you should be aware of them when using FIFOs.
When you write too much content to a FIFO at a time, it can get stuck because a pipe has a limited capacity. The limit depends on the implementation of the pipe. When a pipe gets filled up with data, write operations will block until the pipe is drained from the other side (or raise an error if the pipe was opened with non-blocking mode).
File.mkfifo('fifo')
Thread.new do
File.open('fifo') do |f|
sleep 10
f.read
end
end
File.write 'fifo', 'a'*65536*2
puts 'wrote!'
On most Linux machines, the output “wrote!” in the example above will show up after about 10 seconds after running this code because the File.write
will block until f.read
in the other thread is called.
Sometimes you might want to send an end-of-file (EOF) explicitly to the other side of the pipe to tell a boundary of data. Then you have to close the pipe to send the EOF.
File.mkfifo('fifo') unless File.exist?('fifo')
Thread.new do
loop do
puts File.read('fifo')
end
end
loop do
f = File.open('fifo', 'w')
f.write Time.now.to_s
ensure
f&.close
sleep 1
end
This example shows the current time every second (Ctrl+C to stop). To make the File.read
in the other thread in this example, the writer on the main thread has to close the pipe to send an EOF.
When opening a FIFO, both sides must be opened. In other words, one side cannot be opened until the other side is being opened. The following example will never stop because the reader cannot finish opening the pipe because it is not opened for writing by anyone (Ctrl+C to stop).
File.mkfifo('fifo') unless File.exist?('fifo')
File.open 'fifo'