input without blocking

Y

yahn

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.
 
E

Eustaquio Rangel de Oliveira J

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

Maybe you're looking for:

taq@taq$ irb
irb(main):001:0> require "timeout"
=3D> true
irb(main):002:0> s =3D
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,
 
E

Eric Hodel

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.
 
B

brian yahn

Eric said:
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 Hodel - (e-mail address removed) - 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.
 
J

Joel VanderWerf

brian said:
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.

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.
 
K

karl_brodowsky

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.
 
A

ara.t.howard

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
 
G

gwtmp01

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 Wright
 
A

ara.t.howard

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
 
B

brian yahn

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.
 
A

Andrew Johnson

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 = <STDIN>;
print "Got $foo\n";

doesn't block and finishes immediately.

andrew
 
A

ara.t.howard

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
 
B

brian yahn

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.
 
A

ara.t.howard

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 = <STDIN>;
print "Got $foo\n";

doesn't block and finishes immediately.

andrew

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

-a
 
A

ara.t.howard

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
 
M

Matthew Smillie

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 <iostream>
#include <string>
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.
 
E

Ernest Obusek

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
 
J

James Edward Gray II

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 Gray II
 

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
474,204
Messages
2,571,061
Members
47,668
Latest member
SamiraShac

Latest Threads

Top