[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Non-blocking 'gets' ?

Stephen Ware

10/3/2007 5:46:00 PM

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

26 Answers

tm_calfeld

10/3/2007 7:55:00 PM

0

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 Ware 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.
>
> Any suggestions? Thanks!
> -Stephen
> --
> Posted via http://www.ruby-....
>

--

[PGP Key available at www.keyserver.net - http://homepag...
calfeld]



7stud 7stud

10/3/2007 8:56:00 PM

0

Stephen Ware 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?
--
Posted via http://www.ruby-....

7stud 7stud

10/3/2007 9:58:00 PM

0

Stephen Ware 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.

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

Stephen Ware

10/3/2007 10:17:00 PM

0

> 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?

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

Stephen Ware

10/3/2007 10:18:00 PM

0

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

7stud 7stud

10/3/2007 10:22:00 PM

0

Stephen Ware 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?
--
Posted via http://www.ruby-....

Stephen Ware

10/3/2007 10:25:00 PM

0

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

Rudi Cilibrasi

10/3/2007 10:32:00 PM

0

On 10/3/07, 7stud -- <dolgun@excite.com> wrote:
> Stephen Ware 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/c...

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.


--
"We can try to do it by breaking free of the mental prison of
separation and exclusion and see the world in its interconnectedness
and non-separability, allowing new alternatives to emerge." -- after
Vandana Shiva

Stephen Ware

10/3/2007 10:33:00 PM

0

I'm using a Windows XP 'cmd' shell if that has anything to do with it.
--
Posted via http://www.ruby-....

Stephen Ware

10/3/2007 10:35:00 PM

0

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