Input without blocking


#1

How do you do something like gets but without blocking? All I want to
do is try to see if anything was input and if it wasn’t then just go on
running the rest of my code.


#2

How do you do something like gets but without
blocking? All I want to
do is try to see if anything was input and if it
wasn’t then just go on
running the rest of my code.

Maybe you’re looking for:

taq@taq$ irb
irb(main):001:0> require “timeout”
=> true
irb(main):002:0> s =
irb(main):003:0* begin
irb(main):004:1* timeout(5) do
irb(main):005:2* gets
irb(main):006:2> end
irb(main):007:1> rescue TimeoutError
irb(main):008:1> “”
irb(main):009:1> end

If on 5 seconds you don’t type something, s will be an
empty string.

Best regards,


#3

On Mar 26, 2006, at 6:52 PM, yahn wrote:

How do you do something like gets but without blocking? All I want to
do is try to see if anything was input and if it wasn’t then just
go on
running the rest of my code.

Use threads.

In one thread perform your IO. In your other thread do whatever it
is you’d like to do while waiting for IO.


Eric H. - removed_email_address@domain.invalid - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com


#4

Eric H. wrote:

On Mar 26, 2006, at 6:52 PM, yahn wrote:

How do you do something like gets but without blocking? All I want to
do is try to see if anything was input and if it wasn’t then just
go on
running the rest of my code.

Use threads.

In one thread perform your IO. In your other thread do whatever it
is you’d like to do while waiting for IO.


Eric H. - removed_email_address@domain.invalid - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com

Ok thats one way to do it, but doesn’t ruby have an actual way of just
seeing if any input has been performed? Unnecessary threads will just
slow down the program.


#5

brian yahn wrote:

is you’d like to do while waiting for IO.

A thread won’t cost much if it is just waiting for input.

If the other tasks that are being handled by your program are driven by
IO, then you could use select from a single one thread. (That’s more or
less what is going on when you have multiple ruby threads each handling
their own IO.)

Or you could use select with a timeout of 0 to check if input is
available on $stdin.

print "type something> "; $stdout.flush
loop do
sleep 0.1; print “.”; $stdout.flush
if IO.select([$stdin], [], [], 0)
str = $stdin.gets
break unless str
puts “You typed #{str.inspect}”
print "type something> "; $stdout.flush
end
end

The #sleep call and the print “.” is just to emulate the effect of the
program running while the user is typing.

However, I expect that it will be easier to make the program feel
responsive if you use threads, and let ruby’s thread scheduler handle
the timing.


#6

There should be methods on Unix and Linux using select or something
like that. At least Unix and Posix provide the functionality you are
asking already at OS-level, so it is just a matter of if and how to
access this from Ruby. I would prefer this OS-dependent approach.


#7

On Tue, 28 Mar 2006 removed_email_address@domain.invalid wrote:

There should be methods on Unix and Linux using select or something like
that. At least Unix and Posix provide the functionality you are asking
already at OS-level, so it is just a matter of if and how to access this
from Ruby. I would prefer this OS-dependent approach.

here ya go:

 harp:~ > cat a.rb
 require 'io/wait'

 puts Time.now
 STDIN.wait unless STDIN.ready?
 puts Time.now

 puts STDIN.gets

 harp:~ > cat b.rb
 sleep 2
 puts 42


 harp:~ > ruby b.rb | ruby a.rb
 Mon Mar 27 16:10:42 MST 2006
 Mon Mar 27 16:10:44 MST 2006
 42

kind regards.

-a


#8

On Tue, 28 Mar 2006 removed_email_address@domain.invalid wrote:

On Mar 27, 2006, at 6:11 PM, removed_email_address@domain.invalid wrote:

STDIN.wait unless STDIN.ready?

I might be missing something here but couldn’t another thread
read any pending input after STDIN.ready? has returned true and
before STIN.wait is called? That would result in STDIN.wait
blocking for more input, correct?

sort of - STDIN.wait simply returns when a read from the io would not
block,
so having input OR being at the end of file, for example, might cause it
to
return. thread safety must indeed be handled too.

-a


#9

Wouldn’t this:

 puts Time.now
 STDIN.wait unless STDIN.ready?
 puts Time.now

 puts STDIN.gets

block until something is input? Thats not what I want to do. Unless
wait is deceiving, I don’t see how this would do what I want.


#10

On Mar 27, 2006, at 6:11 PM, removed_email_address@domain.invalid wrote:

STDIN.wait unless STDIN.ready?

I might be missing something here but couldn’t another thread
read any pending input after STDIN.ready? has returned true and
before STIN.wait is called? That would result in STDIN.wait
blocking for more input, correct?

Gary W.


#11

On Mon, 27 Mar 2006 11:52:10 +0900, yahn removed_email_address@domain.invalid wrote:

How do you do something like gets but without blocking? All I want to
do is try to see if anything was input and if it wasn’t then just go on
running the rest of my code.

I was going to suggest using the Fcntl extension to set the non-blocking
bit on the filehandle as an alternative, but it appears to not be
working
(at least on my linux box). That is to say, this script sits and waits
for
input:

require ‘fcntl’

flags = STDIN.fcntl(Fcntl::F_GETFL, 0)
flags |= Fcntl::O_NONBLOCK
STDIN.fcntl(Fcntl::F_SETFL, flags)

a = STDIN.gets
puts “You got #{a}”

Whereas the equivalent Perl script:

use Fcntl;

$flags = fcntl(STDIN,F_GETFL,0);
$flags |= O_NONBLOCK;
fcntl(STDIN,F_SETFL,O_NONBLOCK);

$foo = ;
print “Got $foo\n”;

doesn’t block and finishes immediately.

andrew


#12

On Tue, 28 Mar 2006, brian yahn wrote:

Wouldn’t this:

puts Time.now
STDIN.wait unless STDIN.ready?
puts Time.now

puts STDIN.gets

block until something is input? Thats not what I want to do. Unless
wait is deceiving, I don’t see how this would do what I want.

wait takes a timeout.

you may want to try io/nonblock:

harp:~ > cat a.rb
require ‘io/nonblock’
p STDIN.nonblock{ STDIN.gets }

harp:~ > ruby a.rb </dev/null
nil

harp:~ > ruby a.rb <a.rb
“require ‘io/nonblock’\n”

but you have to realize there really are no ways to tell ‘if something
was
input’ - only ways to tell if a read would block. consider

harp:~ > cat b.rb
print 42
sleep

harp:~ > ruby b.rb|ruby a.rb

but we’re blocking because we used ‘gets’ which reads till newline. the
only
other alternatives are giving a number of bytes to read or using
something like
readpartial

harp:~ > cat a.rb
require ‘io/nonblock’
p STDIN.nonblock{ STDIN.readpartial(2) }

harp:~ > cat b.rb
STDOUT.sync = true
print 42
sleep

harp:~ > ruby b.rb|ruby a.rb
“42”

but even here you hang.

what are you trying to do exactly? the std unix practive of giving ‘-’
as a
command line arg when stdin is meant to be read can neatly avoid this
problem.

regards.

-a


#13

I’m just trying to get the characters being input into the program and
run it at the same time without a thread. A thread is not needed in c++
to do this, so I figured it wouldn’t be needed in ruby. Maybe ruby
isn’t as great as I first thought.


#14

On Tue, 28 Mar 2006, Andrew J. wrote:

require ‘fcntl’

andrew

this seems like a bug… maybe a post to ruby-core?

-a


#15

On Tue, 28 Mar 2006, brian yahn wrote:

I’m just trying to get the characters being input into the program and
run it at the same time without a thread. A thread is not needed in c++
to do this, so I figured it wouldn’t be needed in ruby. Maybe ruby
isn’t as great as I first thought.

probably not:

fortytwo :~ > cat a.rb
require ‘io/nonblock’
p STDIN.nonblock{ STDIN.gets }

fortytwo :~ > ruby a.rb</dev/null
nil

fortytwo :~ > ruby a.rb<a.rb
“require ‘io/nonblock’\n”

-a


#16

On Tue, 28 Mar 2006 13:53:12 +0900, removed_email_address@domain.invalid
removed_email_address@domain.invalid wrote:

this seems like a bug… maybe a post to ruby-core?

Probably a good idea – unless no-one else is seeing this behaviour?

andrew


#17

On Mar 28, 2006, at 9:57, Matthew S. wrote:

STDIN.print "Type away: "
STDIN.flush

Those should, of course, read “STDOUT” rather than “STDIN”.

mea culpa.


#18

I wrote a little timer application and I would like it to play a
sound when the timer has counted down to 0. I looked for a beep
method in the pickaxe book but couldn’t find a standard one. I
searched the web for information about sound support for Ruby and
found something called FMod that runs on my Mac but doesn’t seem to
have Ruby support. I know I can try to wrap that up for Ruby but
before making the effort I thought I’d ask here if anyone knows of
something already available and easy to use for playing sounds in
Ruby on a Mac PowerBook. Oh, I also looked at RUDL but Mac support
looks sketchy and I’d rather go with FMod if necessary.

Thanks,

Ernest


#19

On Mar 28, 2006, at 10:21 AM, Ernest Obusek wrote:

I wrote a little timer application and I would like it to play a
sound when the timer has counted down to 0.

If your needs are very simple, you could print the alarm character:

print “\a”

James Edward G. II


#20

On Mar 28, 2006, at 5:48, brian yahn wrote:

I’m just trying to get the characters being input into the program and
run it at the same time without a thread. A thread is not needed
in c++
to do this.

In the simple case, a thread isn’t needed anywhere:

— Ruby —

STDIN.print "Type away: "
STDIN.flush
10.times do
#something pointlessly time-consuming
end
input = STDIN.gets
puts “You typed: #{input}”

— C++ —

#include
#include
using namespace std;

int main() {
cout >> "Type away: "
for (int i = 0; i < 10; i++) {
// something pointlessly time-consuming
}
string input;
cin >> input;
cout << "You typed: " << input << “\n”
return 0;
}

No thread, no blocking (unless the typist is particularly slow). The
C++ version, if you run it, will only grab one word from the input,
but as an example I’m sure you get the idea.

Apart from that sort of thing, I’d be interested to know exactly how C
++ doesn’t require a separate thread/process to handle input. I
suspect that it’s simply just being created by whatever library
you’re using.

matthew smillie.