Bill Kelly
1/8/2006 5:49:00 PM
From: "Jacek Olszak" <jacekolszak@o2.pl>
>
> I've a simple question - how can I write an application with two
> threads, where first thread reads the user input. I want both threads to
> run SIMULTANEOUSLY.
> So .. here is my code:
>
> a=Thread.new do
> $stdin.gets
> end
>
> b=Thread.new do
> 5.times do
> print "b"
> $stdout.flush
> Thread.pass
> end
> end
>
> a.join
> b.join
>
> Unfortunelty "gets" block my whole application - the "b" thread waits
> until user writes something to the stdin. But I want the b thread not
> wait and run at the same time.
This tends to be a problem with Windows ruby. It seems unlikely to be
resolved until Ruby gets native threads (on the horizon with YARV.)
Here's how I've worked around it. If anyone knows a better way, please
share:
if RUBY_PLATFORM =~ /win32/
require 'Win32API'
$win32_console_kbhit = Win32API.new("msvcrt", "_kbhit", [], 'I')
def console_input_ready?
$win32_console_kbhit.call != 0
end
def nonblocking_stdin_gets
sleep(0.1) until console_input_ready?
$stdin.gets # don't bother to use getc, it also blocks until user hits <return>
end
else
def nonblocking_stdin_gets
$stdin.gets # it just works, on unix
end
end
So you can use nonblocking_stdin_gets in place of $stdin.gets. It's an
imperfect solution, though. It will be nonblocking _until_ the user starts
typing. Then it will block until they hit <return>. (Note, I've tried doing
it character-by-character, with $stdin.getc or $stdin.sysread(1), but it
still blocks until the user hits <return>.) There's probably a way to put
the windows console into unbuffered mode, which would improve this
hack (so we could use $stdin.getc in conjunction with console_input_ready?.)
Anyway, hope this helps . . .
Regards,
Bill