# Trouble with mkfifo and forks

**URL:** <https://rubytalk.org/t/trouble-with-mkfifo-and-forks/59943>\
**Category:** ruby-talk\
**Created:** [6 September 2010 20:10 UTC](https://rubytalk.org/t/trouble-with-mkfifo-and-forks/59943 "2010-09-06T20:10:18Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Josh1](https://avatars.discourse-cdn.com/v4/letter/j/71c47a/32.png) [@Josh1](https://rubytalk.org/u/Josh1)\
**Post date:** [6 September 2010 20:10 UTC](https://rubytalk.org/t/trouble-with-mkfifo-and-forks/59943/1 "2010-09-06T20:10:18Z")

</div>

# In a nutshell:  
1) Create a pipe  
2) Fork twice  
3) Each for sends 10 strings over the pipe  
4) See what comes out the other side

So, why isn't what I send coming out?

class WaitListTest \< Test::Unit::TestCase  
&nbsp;&nbsp;NUMBER\_OF\_ORDERS = 2  
&nbsp;&nbsp;PIPE = "test/wl\_pipe"

&nbsp;&nbsp;def setup  
&nbsp;&nbsp;&nbsp;&nbsp;`rm #{PIPE}`  
&nbsp;&nbsp;&nbsp;&nbsp;`mkfifo #{PIPE}`  
&nbsp;&nbsp;end

&nbsp;&nbsp;def test\_registering\_last\_race  
&nbsp;&nbsp;&nbsp;&nbsp;term\_count = 0  
&nbsp;&nbsp;&nbsp;&nbsp;responses = []  
&nbsp;&nbsp;&nbsp;&nbsp;pids = []

&nbsp;&nbsp;&nbsp;&nbsp;NUMBER\_OF\_ORDERS.times do |i|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pids \<\< Process.fork do  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sleep 1 + (0.1 \* i)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;10.times do |a|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File.open("#{RAILS\_ROOT}/#{PIPE}", "w+") do |pipe|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sleep 0.1  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pipe.puts "Fork #{i} - #{a}"  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File.open("#{RAILS\_ROOT}/#{PIPE}", "a") do |pipe|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sleep 0.1  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pipe.puts "DONE"  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;while term\_count \< NUMBER\_OF\_ORDERS  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File.open("#{RAILS\_ROOT}/#{PIPE}", "r+") do |pipe|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;val = pipe.gets  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if val.match(/DONE/)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;term\_count += 1  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;responses \<\< val  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;puts responses.sort  
&nbsp;&nbsp;&nbsp;&nbsp;puts responses.count  
&nbsp;&nbsp;end  
end

# output  
Started  
Fork 0 - 0  
Fork 0 - 1  
Fork 0 - 2  
Fork 0 - 3  
Fork 0 - 4  
Fork 0 - 5  
Fork 0 - 7  
Fork 0 - 9  
Fork 1 - 0  
Fork 1 - 1  
Fork 1 - 2  
Fork 1 - 3  
Fork 1 - 4  
Fork 1 - 5  
Fork 1 - 7  
Fork 1 - 8  
Fork 1 - 9  
17

Why isn't this 20?

---

<div class="post-metadata">

**Author:** ![Joel\_VanderWerf](https://avatars.discourse-cdn.com/v4/letter/j/e19b73/32.png) [@Joel\_VanderWerf](https://rubytalk.org/u/Joel_VanderWerf)\
**Post date:** [6 September 2010 21:53 UTC](https://rubytalk.org/t/trouble-with-mkfifo-and-forks/59943/2 "2010-09-06T21:53:13Z")

</div>

I'm probably naive about something, but fifos almost never work right for what I want to do, and I usually end up using (unix domain) sockets (which also makes it easier to move to tcp sockets if you need to distribute across hosts).

Anyway, in your code, it seems that the repeated closing of the \*read\* end of the pipe causes some data to be lost. If you can modify your read loop to keep using the same IO object, it seems to work (see below). Also, I found I needed to watch for #gets returning nil (though that doesn't happen reliably).

Perhaps someone who knows more about pipes will "pipe up" on this thread.

class WaitListTest  
&nbsp;&nbsp;&nbsp;NUMBER\_OF\_ORDERS = 2  
&nbsp;&nbsp;&nbsp;PIPE = File.expand\_path("~/tmp/wl\_pipe")

&nbsp;&nbsp;&nbsp;def setup  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`rm -f #{PIPE}`  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`mkfifo #{PIPE}`  
&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;def test\_registering\_last\_race  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;term\_count = 0  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;responses =   
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pids =

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NUMBER\_OF\_ORDERS.times do |i|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pids \<\< Process.fork do  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sleep 0.1 + (0.1 \* i)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;10.times do |a|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File.open(PIPE, "w") do |pipe|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sleep 0.1  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pipe.puts "Fork #{i} - #{a}"  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File.open(PIPE, "w") do |pipe|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sleep 0.1  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pipe.puts "DONE"  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pipe = File.open(PIPE, "r")  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while term\_count \< NUMBER\_OF\_ORDERS  
# File.open(PIPE, "r") do |pipe|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;val = pipe.gets  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case val  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when /DONE/  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;term\_count += 1  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when nil  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts "pipe closed" # need this too  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;responses \<\< val  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
# end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pids.each do |pid|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Process.waitpid(pid)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts responses.sort  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts responses.count  
&nbsp;&nbsp;&nbsp;end  
end

wlt = WaitListTest.new  
wlt.setup  
wlt.test\_registering\_last\_race

> **···**
>
> On 09/06/2010 01:10 PM, Josh wrote:
> 
> > # In a nutshell:  
> > 1) Create a pipe  
> > 2) Fork twice  
> > 3) Each for sends 10 strings over the pipe  
> > 4) See what comes out the other side

---

<div class="post-metadata">

**Author:** ![Brian\_Candler](https://avatars.discourse-cdn.com/v4/letter/b/5f9b8f/32.png) [@Brian\_Candler](https://rubytalk.org/u/Brian_Candler)\
**Post date:** [7 September 2010 08:40 UTC](https://rubytalk.org/t/trouble-with-mkfifo-and-forks/59943/3 "2010-09-07T08:40:21Z")

</div>

In the receiver, you are constantly opening the pipe for read and then  
closing it. I expect that if someone writes to the pipe while there's no  
reader, the data is lost.

The program works for me if I swap the open and while around:

&nbsp;&nbsp;&nbsp;&nbsp;File.open("#{RAILS\_ROOT}/#{PIPE}", "r") do |pipe|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while term\_count \< NUMBER\_OF\_ORDERS  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;val = pipe.gets  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if val.match(/DONE/)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.. etc

But it is much better form to create an anonymous pipe in the parent  
(rd, wr = IO.pipe) then fork. Close the rd end in the child and the wr  
end in the parent.

Use Socket.pair if you want a bidirectional channel.

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/](http://www.ruby-forum.com/).
