NUMBER_OF_ORDERS.times do |i|
pids << Process.fork do
sleep 1 + (0.1 * i)
10.times do |a|
File.open("#{RAILS_ROOT}/#{PIPE}", "w+") do |pipe|
sleep 0.1
pipe.puts "Fork #{i} - #{a}"
end
end
File.open("#{RAILS_ROOT}/#{PIPE}", "a") do |pipe|
sleep 0.1
pipe.puts "DONE"
end
end
end
while term_count < NUMBER_OF_ORDERS
File.open("#{RAILS_ROOT}/#{PIPE}", "r+") do |pipe|
val = pipe.gets
if val.match(/DONE/)
term_count += 1
else
responses << val
end
end
end
puts responses.sort
puts responses.count
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
NUMBER_OF_ORDERS = 2
PIPE = File.expand_path("~/tmp/wl_pipe")
NUMBER_OF_ORDERS.times do |i|
pids << Process.fork do
sleep 0.1 + (0.1 * i)
10.times do |a|
File.open(PIPE, "w") do |pipe|
sleep 0.1
pipe.puts "Fork #{i} - #{a}"
end
end
File.open(PIPE, "w") do |pipe|
sleep 0.1
pipe.puts "DONE"
end
end
end
pipe = File.open(PIPE, "r")
while term_count < NUMBER_OF_ORDERS
File.open(PIPE, “r”) do |pipe|
val = pipe.gets
case val
when /DONE/
term_count += 1
when nil
puts "pipe closed" # need this too
else
responses << val
end
end
end
pids.each do |pid|
Process.waitpid(pid)
end
puts responses.sort
puts responses.count
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:
File.open("#{RAILS_ROOT}/#{PIPE}", "r") do |pipe|
while term_count < NUMBER_OF_ORDERS
val = pipe.gets
if val.match(/DONE/)
.. 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.
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.