How to make non-blocking call to cin?

P

puzzlecracker

is it even possible or/and there is a better alternative to accept
input in a nonblocking manner?
 
J

James Kanze

You could try using 'peek' member function. You should get
'eof' if no input is available, I am guessing, but don't take
my word for it, RTFM and experiment.

Peek will wait for a character is one isn't available.
Basically, peek() is like get(), except that it doesn't extract
the character from the stream.
 
L

Lionel B

is it even possible

I don't believe it is in an OS-independent way. I don't think C++ has a
notion of non-blocking I/O at all - a read failure is always simply
treated as an "error".

Maybe have a look at the Boost.Iostreams library:

http://www.boost.org/doc/libs/1_36_0/libs/iostreams/doc/index.html

and in particular section 3.6 (Asynchronous and Non-Blocking I/O). But I
get the impression it's not quite there yet.
or/and there is a better alternative to accept input
in a nonblocking manner?

I'm not sure what you mean here.

What are you actually trying to do? I can tell you how to put stdin into
non-blocking mode on a POSIX (e.g. Linux) terminal, if you're interested
(and also how to make it non line-buffered, which you probably want too
in that case).
 
P

puzzlecracker

I don't believe it is in an OS-independent way. I don't think C++ has a
notion of non-blocking I/O at all - a read failure is always simply
treated as an "error".

Maybe have a look at the Boost.Iostreams library:

http://www.boost.org/doc/libs/1_36_0/libs/iostreams/doc/index.html

and in particular section 3.6 (Asynchronous and Non-Blocking I/O). But I
get the impression it's not quite there yet.


I'm not sure what you mean here.

What are you actually trying to do? I can tell you how to put stdin into
non-blocking mode on a POSIX (e.g. Linux) terminal, if you're interested
(and also how to make it non line-buffered, which you probably want too
in that case).

Sure, I am actually building apps on Linux, hence posix works. Can't
use boost. Please demonstrate it(please don't flame me for OT)

Thanks
 
I

Ian Collins

puzzlecracker said:
is it even possible or/and there is a better alternative to accept
input in a nonblocking manner?

Is what possible? Ah, I see you have hidden the question in your
subject line.

If you want non-blocking I/O, you probably don't want iostreams, at
least not using standard streambufs. How would you differentiate a
"would block" condition from an end of file?

You can use non-blocking I/O, but you'd have to provide your own
streambuf object.
 
J

James Kanze

[...]
If you want non-blocking I/O, you probably don't want iostreams, at
least not using standard streambufs. How would you differentiate a
"would block" condition from an end of file?
You can use non-blocking I/O, but you'd have to provide your own
streambuf object.

Even then, you'd have to use it outside of the normal [io]stream
interface; [io]stream will memorize any "failure". Perhaps in
collaboration with istream::readsome.
 
L

Lionel B

Sure, I am actually building apps on Linux, hence posix works. Can't use
boost. Please demonstrate it(please don't flame me for OT)

I won't, but someone else possibly will ;)

Here's some pretty crude code - to put stdin into non-blocking mode:

#include <unistd.h>
#include <fcntl.h>

const int fd = fileno(stdin);
const int fcflags = fcntl(fd,F_GETFL);
if (fcflags<0) { ... /* handle error */}
if (fcntl(fd,F_SETFL,fcflags | O_NONBLOCK) <0) { ... /* handle error */} // set non-blocking

"man fcntl" for more info.

To un-line buffer stdin (i.e. set terminal to "raw" mode):

#include <unistd.h>
#include <termios.h>

const int fd = fileno(stdin);
termios tcflags;
if (tcgetattr(fd,&tcflags)<0) { ... /* handle error */}
tcflags.c_lflag &= ~ICANON; // set raw mode (unset canonical modes)
if (tcsetattr(fd,TCSANOW,&tcflags)<0) { ... /* handle error */}

"man termios" for more info.

Now calls to "getchar()" and friends won't be line buffered and won't block.

"man getchar" for more info.

There is a slightly simpler way to achieve both without the "fcntl" call too:

#include <unistd.h>
#include <termios.h>

// un-line buffer stdin and optionally set non-blocking
void set_stdin(const bool block /* false for non-blocking */)
{
const int fd = fileno(stdin);
termios flags;
if (tcgetattr(fd,&flags)<0) { ... /* handle error */}
flags.c_lflag &= ~ICANON; // set raw (unset canonical modes)
flags.c_cc[VMIN] = block; // i.e. min 1 char for blocking, 0 chars for non-blocking
flags.c_cc[VTIME] = 0; // block if waiting for char
if (tcsetattr(fd,TCSANOW,&flags)<0) { ... /* handle error */}
}

Of course you need to reset all control flags to get back to normal after.
any of these calls.

HTH,
 
J

James Kanze

I won't, but someone else possibly will ;)

Well, since he knows it's off topic, and he knows the group
where it would be on topic (and where he's really more likely to
get a complete answer): comp.unix.programmer.

It's fairly tricky. I wouldn't try it from std::cin, at least
not to begin with. Just set up fd 0 and read from it. (If
you're reading one character at a time, with no buffering,
istream and streambuf really don't buy you anything but
portability. Which he'll have lost anyway.)
 
L

Lionel B

I'd avoid the problem altogether:

I'd simply create a cin reader thread whose job would be to read input
safely from a blocking cin. It could also be charged with validating
this input if desirable.

I'd put a thread safe FIFO communication mechanism between the two
threads (e.g. mutex protected std::queue) and the main process thread
would peek if there is a message on the queue for it, if so, read and
process it, if not, continue with its other tasks.

To me, that sounds simpler than trying to turn cin as non-blocking. plus
anyway, non-blocking cin would think that there is data to be read if
only one character was present in the buffer but you may wish to get
input as complete words (lines?) and not interrupt normal processing
until a complete word is available. This would be trivial to do with
the input thread model but much more difficult with a non-blocking cin
or stdin.

That sounds pretty complicated to me... but then I really don't know how
you'd make cin non-blocking (or non-line-buffered, for that matter), so I
don't know how complicated that would be.

But if you're prepared to forgo cin and use stdin, then (at least in
unix) it's pretty straightforward - including getting line-buffered
input in non-blocking mode. See e.g. my simple stdin control utilities
and demo:

ftp://ftp.informatics.sussex.ac.uk/pub/users/lionelb/misc/stdin_control
 

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

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,682
Members
48,796
Latest member
Greg L.

Latest Threads

Top