Non-blocking 'gets'?

Hi guys, sorry if this is a stupid question, but I’ve been reading
around online and in ‘Programming Ruby,’ and I can’t find anything.

Is there a way to perform a non-blocking gets or getc? As in a method
that reads a character from stdin if there is one in the buffer or
returns nil otherwise? I’m writing a multi-threaded application that
communicates over the internet using sockets, but I want the person who
runs the script on the host machine to be able to enter commands via
stdin. The ‘gets’ command hangs all my threads until it returns.

Any suggestions? Thanks!
-Stephen

One option is use Kernel.select, or, equivalently, IO.select.

Basically, select waits for input on some ios. But it allows for a
timeout value which I believe can be 0.

Another option is to use fcntl with F_SETFL and O_NONBLOCK.

e.g.:

requite ‘fcntl’
STDIN.fcntl(Fcntl::F_SETFL,Fcntl::O_NONBLOCK)
STDIN.read

Will throw an Errno:EAGAIN if there is no input.

Note that gets waits for a newline so will still block.

c.

On Oct 3, 2007, at 12:46 PM, Stephen W. wrote:

Any suggestions? Thanks!
-Stephen

Posted via http://www.ruby-forum.com/.

[PGP Key available at www.keyserver.net - http://homepage.mac.com/
calfeld]

Stephen W. wrote:

Hi guys, sorry if this is a stupid question, but I’ve been reading
around online and in ‘Programming Ruby,’ and I can’t find anything.

Is there a way to perform a non-blocking gets or getc? As in a method
that reads a character from stdin if there is one in the buffer or
returns nil otherwise? I’m writing a multi-threaded application that
communicates over the internet using sockets, but I want the person who
runs the script on the host machine to be able to enter commands via
stdin. The ‘gets’ command hangs all my threads until it returns.

If you don’t wait for the user to input something, how can there ever be
input in a buffer?

Stephen W. wrote:

Is there a way to perform a non-blocking gets or getc? As in a method
that reads a character from stdin if there is one in the buffer or
returns nil otherwise? I’m writing a multi-threaded application that
communicates over the internet using sockets, but I want the person who
runs the script on the host machine to be able to enter commands via
stdin. The ‘gets’ command hangs all my threads until it returns.

It doesn’t sound like you are writing a multi-threaded application if
gets hangs all your threads. The whole point of threads is to execute
other blocks of code while there is idle time in a given block of code.

One option is use Kernel.select, or, equivalently, IO.select.

Basically, select waits for input on some ios. But it allows for a
timeout value which I believe can be 0.

I tried this, but no luck. The command works, but it’s the same
problem… every thread is suspended until it returns.

Another option is to use fcntl with F_SETFL and O_NONBLOCK.

e.g.:

requite ‘fcntl’
STDIN.fcntl(Fcntl::F_SETFL,Fcntl::O_NONBLOCK)
STDIN.read

Will throw an Errno:EAGAIN if there is no input.

Hmm. I might try this if nothing else works, but that’s going to be a
lot of wasted clock cycles. Ideally, the thread would just sleep until
STDIN has something in it. Is there no way to accomplish that?

If you don’t wait for the user to input something, how can there ever be
input in a buffer?

The idea is that while I’m waiting for input from STDIN, the other
threads in the application are still running.

Stephen W. wrote:

Hi guys, sorry if this is a stupid question, but I’ve been reading
around online and in ‘Programming Ruby,’ and I can’t find anything.

Is there a way to perform a non-blocking gets or getc? As in a method
that reads a character from stdin if there is one in the buffer or
returns nil otherwise? I’m writing a multi-threaded application that
communicates over the internet using sockets, but I want the person who
runs the script on the host machine to be able to enter commands via
stdin. The ‘gets’ command hangs all my threads until it returns.

The following is an example that uses one thread to execute some code in
the background while another thread waits for user input. After being
prompted for input, if you wait 5 seconds before entering any input, you
will see that the background thread’s output is written to the file
while the main thread waits for your input.

If instead, you enter your input right away, you will see that what you
entered will be interleaved with the thread’s output.

require “monitor”

f = File.new(“aaa.txt”, “w”)
lock = Monitor.new

t = Thread.new do
lock.synchronize do
f.puts(“thread output1”)
end

sleep(3)

lock.synchronize do
f.puts(“thread output2”)
end
end

print "Enter command: "
STDOUT.flush
input = gets

lock.synchronize do
f.puts(input)
end

t.join
f.close

File.open(“aaa.txt”) do |file|
print file.read
end

–output:–
(waiting 5 seconds):
Enter command: hello
thread ouput1
thread output2
hello

(entering input immediately when prompted):
Enter command: hello
thread output1
hello
thread output2

One thing I found puzzling is having to call STOUT.flush. When I don’t
include that statement, then the print statement is skipped. Yet, if I
use puts instead of print, then the flush call isn’t necessary. Anyone
know why?

It doesn’t sound like you are writing a multi-threaded application if
gets hangs all your threads. The whole point of threads is to execute
other blocks of code while there is idle time in a given block of code.

Well… I think my code is written properly. For simplicity’s sake,
let’s consider it a chat room. The main thread spawns a “listener”
thread and then sleeps forever. The listener thread listens for socket
connections on a port and spawns a new thread for each socket, basically
allowing multiple users to connect at the same time and interact with
one another. That much works, and I have logged in with multiple users
to test it.

The change I’m trying to make is in the main thread… instead of
sleeping forever, I want to accept commands from STDIN, such as
‘shutdown,’ for example. But when I replaced ‘sleep(0)’ with an
infinite loop of ‘command = gets’, it freezes the whole application. I
am no longer able to connect, even with one user. Actually, it will
still connect but only if I type characters into STDIN very rapidly.
That’s what leads me to conclude that ‘gets’ is hanging all my threads.

On 10/3/07, 7stud – [email protected] wrote:

Stephen W. wrote:
One thing I found puzzling is having to call STOUT.flush. When I don’t
include that statement, then the print statement is skipped. Yet, if I
use puts instead of print, then the flush call isn’t necessary. Anyone
know why?

I guess it’s because in Unix most text I/O at the text console is
line-buffered by default. See “cooked mode” e.g.
http://meshier.com/docs/oreilly/unix2/upt/ch41_02.htm

for more info. Roughly, the kernel is expected to collect input into
lines,
and to allow stuff like backspace to work simply, it has to buffer a
whole line
up and wait for return before sending it on to the application. So that
is why
your print doesn’t print: it is not sending the return to cause the
flush. But
sending one yourself fixes it. The puts has the \n so the flush
happens automatically I guess.

I’m using a Windows XP ‘cmd’ shell if that has anything to do with it.

But when I replaced ‘sleep(0)’ with an
infinite loop of ‘command = gets’, it freezes the whole application.

Correction: it was an infinite loop of ‘sleep(1)’ commands.

Rudi C. wrote:

On 10/3/07, 7stud – [email protected] wrote:

Stephen W. wrote:
One thing I found puzzling is having to call STOUT.flush. When I don’t
include that statement, then the print statement is skipped. Yet, if I
use puts instead of print, then the flush call isn’t necessary. Anyone
know why?

I guess it’s because in Unix most text I/O at the text console is
line-buffered by default. See “cooked mode” e.g.
http://meshier.com/docs/oreilly/unix2/upt/ch41_02.htm

for more info. Roughly, the kernel is expected to collect input into
lines,
and to allow stuff like backspace to work simply, it has to buffer a
whole line
up and wait for return before sending it on to the application. So that
is why
your print doesn’t print: it is not sending the return to cause the
flush. But
sending one yourself fixes it. The puts has the \n so the flush
happens automatically I guess.

Then why does this print command produce output without a call to flush:

print "Enter data: "
line = gets

One thing I found puzzling is having to call STOUT.flush. When I don’t
include that statement, then the print statement is skipped. Yet, if I
use puts instead of print, then the flush call isn’t necessary. Anyone
know why?

stdout is auto-flushed on newlines. puts includes a newline, print
doesn’t.

mfg, simon … l

Rudi C. wrote:

I would presume the “main”
(first) thread would be the only one able to take advantage of this
feature. Does that make sense?

No, because if you look at the example I posted, the main thread has the
statements:

print "Enter command: "
STDOUT.flush
input = gets

According to your explanation, the flush call should be unnecessary.

Simon K. wrote:

One thing I found puzzling is having to call STOUT.flush. When I don’t
include that statement, then the print statement is skipped. Yet, if I
use puts instead of print, then the flush call isn’t necessary. Anyone
know why?

stdout is auto-flushed on newlines. puts includes a newline, print
doesn’t.

Then how come this program:

print "Enter command: "
input = gets

displays "Enter command: " to my terminal?

line = gets

I would imagine because it is the interactive terminal (not
backgrounded, probably first thread right?) and so the gets itself
causes a flush of the associated file descriptor automatically. That
is, stdin and stdout are linked in this way so that reading from stdin
triggers a flush for stdout first. This happens in order to support
prompting at interactive terminals, but obviously only one thread is
supposed to read from stdin at the same time so only one is granted
the special power of having a linked stdin / stdout. I think
non-interactive output (not a tty) is not linked this way so you don’t
get extra convenient flushing for free. I would presume the “main”
(first) thread would be the only one able to take advantage of this
feature. Does that make sense?
I would imagine the behavior is similar under windows also but I
noticed there are sometimes differences. Like stdout and stderr are
usually not different under windows. Cheers, -r.

Err… does anyone have an answer to my original question?

hmm, well the first-thread thing was really a guess. i don’t know
what else would
cause the different behvaior but perhaps there is another reason one
thread is privileged over another in terms of interactive terminal
ownership. the only other thing i can think of is that somehow the
“interactive terminal” indication is switched around. maybe as a
result of the backtick or something? i have also experienced strange
behavior with puts and gets but always chalked it up to one of the two
issues we’ve mentioned: buffering (with newline interactions) and
linked stdin-stdout file descriptor pairs. i wish i had a simpler
explanation to offer but i suspect we are on the right track because
somebody else said something similar to what i did. cheers, -r.

I’m pretty sure you can never put STDIN into a nonblocking mode on
Windows, just FYI.

Maybe that’s the problem :frowning:

It’s certainly possible for sockets though.

Yeah… that’s how I’m doing it now. Basically you have to connect as
an admin user and send commands over a socket.

On Oct 3, 2007, at 5:32 PM, Stephen W. wrote:

I’m using a Windows XP ‘cmd’ shell if that has anything to do with it.

I’m pretty sure you can never put STDIN into a nonblocking mode on
Windows, just FYI. It’s certainly possible for sockets though.

James Edward G. II

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs