Shay Hawkins 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
-- 
Posted via http://www.ruby-forum.com/.