IO.popen with Threads

E

Eikichi On

Hi everyone,

I am trying to use IO.popen in order to put and get messages from a
process to its sub-process (according to
http://ruby-doc.org/core/classes/IO.html#M002242).

I am not experimented and I have two questions about:

1/ Do threads are a good choice, for read and write at the same time
(with IO.popen)?
Have you got a simple exemple?

2/ I think IO.popen is useful for asynchrone communication. But when I
just need to send a message from a process to its sub-process, and wait
its answer, how should we do it? (any example is very appreciated)

Many thanks
 
R

Robert Klemme

Hi everyone,

I am trying to use IO.popen in order to put and get messages from a
process to its sub-process (according to
http://ruby-doc.org/core/classes/IO.html#M002242).

I am not experimented and I have two questions about:

1/ Do threads are a good choice, for read and write at the same time
(with IO.popen)?
Yes.

Have you got a simple exemple?

Please see answer to second question.
2/ I think IO.popen is useful for asynchrone communication. But when I
just need to send a message from a process to its sub-process, and wait
its answer, how should we do it? (any example is very appreciated)

reply = IO.popen ["cat", "-n"], "r+" do |io|
rdr = Thread.new { io.read } # alternative: io.readlines
io.puts "message", "you", "want to send"
io.close_write

rdr.value # joins and fetches the result
end

Kind regards

robert
 
E

Eikichi On

Thank you very much for your answer, Robert. Thanks to your help, I
could start coding. But I have another little problem and I would
appreciate your opinion.

Here is the code I used:

class Test
def initialize(program)
while isready?(program) && cool?(program)
program.puts 'start', 'my name is ...'
# ...
end
end

protected

def process_command(program, command)
begin
rdr = Thread.new { program.read } # alternative: io.readlines
program.puts "#{command}"
program.close_write
rdr.value # joins and fetches the result
end
end

def isready?(program)
reply = process_command(program, 'isready')
reply.chomp.match(/yes_i_am_ready$/)
end

def cool?(program)
reply = process_command(program, 'cool')
reply.chomp.match(/yes_i_am_cool$/)
end
end

program = IO.popen("./program", "w+")

a = Test.new(program)
(...)in `write': not opened for writing (IOError)

As we can see, there is an error when I try to send a message to the
sub-process because of the closure of the stream
(http://ruby-doc.org/core/classes/IO.html#M002289).

I believe that it is not possible to open again a closed stream. Do you
think a good way is to don't close the stream (except at the very end of
the Ruby script)? or should it be better to change the current code
structure?

Thanks again for any help.
 
R

Robert Klemme

2010/3/2 Eikichi On said:
Thank you very much for your answer, Robert. =A0Thanks to your help, I
could start coding. But I have another little problem and I would
appreciate your opinion.

Here is the code I used:

=A0 =A0class Test
=A0 =A0 =A0def initialize(program)
=A0 =A0 =A0 =A0while isready?(program) && cool?(program)
=A0 =A0 =A0 =A0 =A0program.puts 'start', 'my name is ...'
=A0 =A0 =A0 =A0 =A0# ...
=A0 =A0 =A0 =A0end
=A0 =A0 =A0end

=A0 =A0 =A0protected

=A0 =A0 =A0def process_command(program, command)
=A0 =A0 =A0 =A0begin
=A0 =A0 =A0 =A0 =A0rdr =3D Thread.new { program.read } # alternative: io.= readlines
=A0 =A0 =A0 =A0 =A0program.puts "#{command}"
=A0 =A0 =A0 =A0 =A0program.close_write
=A0 =A0 =A0 =A0 =A0rdr.value # joins and fetches the result
=A0 =A0 =A0 =A0end
=A0 =A0 =A0end

=A0 =A0 =A0def isready?(program)
=A0 =A0 =A0 =A0reply =3D process_command(program, 'isready')
=A0 =A0 =A0 =A0reply.chomp.match(/yes_i_am_ready$/)
=A0 =A0 =A0end

=A0 =A0 =A0def cool?(program)
=A0 =A0 =A0 =A0reply =3D process_command(program, 'cool')
=A0 =A0 =A0 =A0reply.chomp.match(/yes_i_am_cool$/)
=A0 =A0 =A0end
=A0 =A0end

program =3D IO.popen("./program", "w+")

a =3D Test.new(program)
(...)in `write': not opened for writing (IOError)

As we can see, there is an error when I try to send a message to the
sub-process because of the closure of the stream
(http://ruby-doc.org/core/classes/IO.html#M002289).

I believe that it is not possible to open again a closed stream.

Exactly that is the source of your error.
=A0Do you
think a good way is to don't close the stream (except at the very end of
the Ruby script)? or should it be better to change the current code
structure?

I would certainly change the structure. I would put the IO.popen
inside the class since you will be writing a class handling a specific
external program - at least that's what seems to be the case here.

When you close the stream depends on the external program you are
executing. There is no general rule I can give you here.

Note that if you need to deal with multiple requests and responses
from the external process I believe there are a number of tools around
for that already. You should be able to find something by searching
for "ruby expect".

Kind regards

robert

--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
 
E

Eikichi On

Thank you for your reply very educational, very clear. I have tested
IO#readline instead of IO#read, but once again I've got a "write" error.
And I don't exactly see how to fix it.

I just would like to establish a such communication (according to a
given protocol) like:

Parent message: Child answer:
-------------- ------------

'are u ready?' 'yes_i_am_ready'
'are u cool?' 'yes_i_am_cool'
'Hello' 'foo'
'my name is ...' 'bar'

Help me please :eek:
 
R

Robert Klemme

2010/3/2 Eikichi On said:
Thank you for your reply very educational, very clear. =A0I have tested
IO#readline instead of IO#read, but once again I've got a "write" error.
And I don't exactly see how to fix it.

I just would like to establish a such communication (according to a
given protocol) like:

Parent message: =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0Child answer:
-------------- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ------------

'are u ready?' =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 'yes_i_am_ready'
'are u cool?' =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0'yes_i_am_cool'
'Hello' =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0'foo'
'my name is ...' =A0 =A0 =A0 =A0 =A0 =A0 =A0 'bar'

Help me please :eek:

That's exactly the "expect" like model. See for example:
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/66884

Kind regards

robert


--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,226
Members
46,816
Latest member
nipsseyhussle

Latest Threads

Top