Shay H. wrote:
I call Open3.popen3 to create the three streams. In a loop, I want to
constantly read input from stderr. (Assuming I assigned the pipes to
stdin, stdout, and stderr variable names.)
loop do
line = stderr.gets()
puts(“Output: #{line}”)
end
Then, if I receive an output of say, 0, I want to input something to the
program through stdin five seconds later.
loop do
line = stderr.gets().strip()
puts(“Output: #{line}”)
if(line == “0”)
Thread.new() do
sleep(5)
stdin.puts(“Received 0 five seconds ago.”)
end
end
end
It creates the thread properly, but when the sleep expires and it is
ready to call stdin.puts(), it cannot do anything, because the loop
continued around and it is reading from stderr.
Perhaps it would be helpful to distinguish symptoms from your assumed
causes.
Firstly, are you saying that the stdin.puts line never completes? You
need to prove this. I suggest:
STDERR.puts "About to send..."
stdin.puts "Received 0"
STDERR.puts "Finished sending."
Secondly, if the puts never completes, are you sure that an exception is
not being raised within your thread? Such exceptions are usually silent,
unless you either join the thread (wait for it to complete), or you set
Thread.abort_on_exception = true
at the top of your program. I suggest you do the latter, to help rule
out a possible cause.
Thirdly, because of buffering, the stuff you wrote to stdin might not
actually be sent until you do
stdin.flush
Or you could do ‘stdin.sync = true’ after opening with popen3, so that
all writes to stdin are flushed automatically.
(So if you see “Finished sending.” but the other program doesn’t appear
to respond, that could be the underlying problem)
However, when it
receives a new set of input from stderr, since the stream is momentarily
being unused, it can then grab the stdin stream and properly input the
old line.
So prove that; e.g. the STDERR.puts “Finished sending.” I suggested
before.
As I mentioned before, I tried using select on stderr so that it
wouldn’t tie up the stream, yet I’ve been told select only works
properly with sockets on Windows.
No, if you are using threads, you do not need to do select.
Actually, Ruby will be using select() behind the scenes, and so if
Windows really is that broken, then you would never be able to run
multiple threads talking on different file descriptions; but I didn’t
think it was quite that broken (you need a Windows expert though, I am
not one)
If the program really only outputs to stderr and nothing to stdout, then
it may be simpler just to redirect stderr to stdout, and then talk to it
using a normal IO.popen. That would be “yourcmd 2>&1” under Linux; I
don’t know what the Windows equivalent would be.
Of course, if it weren’t for the “5 second delay” requirement, then it
could be written quite happily without a thread:
while line = stderr.gets
line.chomp!
puts “Output: #{line}”
if line == “0”
stdin.puts “Sending something now”
stdin.flush
end
end