Announcement (2017-05-07): www.ruby-forum.com is now read-only since I
unfortunately do not have the time to support and maintain the forum any
more. Please see rubyonrails.org/community and ruby-lang.org/en/community
for other Rails- und Ruby-related community platforms.

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

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.

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

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

Rudi Cilibrasi wrote:
> 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/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

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

* 7stud -- <dolgun@excite.com> (00:21) schrieb:
> 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 Cilibrasi 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 Krahnke 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?

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.

On Oct 3, 2007, at 5:32 PM, Stephen Ware 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 Gray II

> I'm pretty sure you can never put STDIN into a nonblocking mode on> Windows, just FYI.
Maybe that's the problem :(
>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.

Wow, that is quite complex. Thank you!
I also managed to discover another usable method: run a 'system' command
in a new thread. That seems to release the blocking on gets by creating
a second process, and as far as I can tell will work on both Windows and
*nix. The downside is that the two processes can't really communicate
with each other much, but in my case I don't need them to.
Thanks everyone for you help :)

Stephen Ware wrote:
> Wow, that is quite complex. Thank you!>> I also managed to discover another usable method: run a 'system' command> in a new thread. That seems to release the blocking on gets by creating> a second process, and as far as I can tell will work on both Windows and> *nix. The downside is that the two processes can't really communicate> with each other much, but in my case I don't need them to.>> Thanks everyone for you help :)
Stephen,
Can you please provide a very simple 'system' command example as I'm
having the same problem.

Wurzel Cidermaker wrote:
> Lloyd Linklater wrote:>> Why don't you just bind a keypress event? That would capture any given>> keystroke in a non blocking way.>> Can you provide an example?
I got the idea from the pickaxe book starting on page 246.

Stephen Ware wrote in post #565434:
> 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
I know this is an old post, but still appears among Google's top
results.
By combinig the various solutions I just read, I came up with a
cross-platform way to solve that problem.
Details here:
http://blog.x-aeon.com/2014/03/26/how-to-read-one-...
The relevant piece of code: a `GetKey.getkey` method
returning the ASCII code or `nil` if none was pressed.
Should work both on Windows and Unix.
module GetKey
# Check if Win32API is accessible or not
@use_stty = begin
require 'Win32API'
false
rescue LoadError
# Use Unix way
true
end
# Return the ASCII code last key pressed, or nil if none
#
# Return::
# * _Integer_: ASCII code of the last key pressed, or nil if none
def self.getkey
if @use_stty
system('stty raw -echo') # => Raw mode, no echo
char = (STDIN.read_nonblock(1).ord rescue nil)
system('stty -raw echo') # => Reset terminal mode
return char
else
return Win32API.new('crtdll', '_kbhit', [ ], 'I').Call.zero? ? nil
: Win32API.new('crtdll', '_getch', [ ], 'L').Call
end
end
end
And here is a simple program to test it:
loop do
k = GetKey.getkey
puts "Key pressed: #{k.inspect}"
sleep 1
end
In the link provided above, I also show how to use the `curses` library,
but the result gets a bit whacky on Windows.
Hope this will help others.