tags:

views:

163

answers:

5

Hi All

I would like to read some data from a stream I have using std::getline. Below a sample using the std::cin.

std::string line;
std::getline( std::cin, line );

This is a blocking function i.e. if there is no data or line to read it blocks execution.

Do you know if exists a function for checking data availability before calling std::getline? I don't want to block.

How can I check whether the stream buffer is full of data valid for a successful call to std::getline?

Whatever looks like the code below

if( dataAvailableInStream() )
{
     std::string line;
     std::getline( std::cin, line );
}

Thanks AFG

+3  A: 

std::iostream provides a peek function that returns the next character in the stream without removing it. So you could do something like the following (totally not tested).

bool dataAvailableInStream( std::iostream &stream )
{
  return stream.peek() != std::iostream::traits_type::eof();
}

Edit

As rubenvb points out, std::cin blocks by design. Therefore the code above will get you past getline blocking, but not cin.

Edit Edit

As Charles points out below, peek blocks if no data is available. Therefore this does not provide a complete solution. It will keep you from blocking on getline, but not blocking overall.

nathan
Or `return stream.peek() != std::eof;` if you're not into verbosity.
Mike Seymour
@Mike lol. I'll edit it to reflect your implementation.
nathan
IT DOESN'T WORK!I tried and peek() blocks as std::getline() does when there is nothing to read.
Abruzzo Forte e Gentile
This is incorrect. `peek()` only returns `traits_type::eof()` if reading the peeked character fails. If the character takes a long time to read (blocked on user input), `peek()` will just take a long time to return.
Charles Bailey
@Abruzzo, as others have pointed out cin blocks. Other stream types, say if you were reading from a file, would not block.
nathan
@Charles, I've reverted the std::eof to the traits_type::eof I had originally.
nathan
Um, there is no `std::traits_type`, I was being short for `std::iostream::traits_type`. That's not the major issue though. "If there is no character it returns an eof trait" is not true. If there is no character `peek()` just blocks in exactly the same way that `get()` would block. `peek()` simply doesn't address the issue that the asker is having.
Charles Bailey
hi all. Please see my note afeter nathan comment right after the question. Apologize to everybody, but I was out for today so I am late.
Abruzzo Forte e Gentile
@Charles, thanks for double checking me. I think I've corrected the answer enough to provide a partial solution to Abruzzo's problem.
nathan
You've still missed of the brackets from the `eof()` call :) . I'm still not convinced how much this answer addresses the original problem as the question definitely calls for an approach that is guaranteed to not block.
Charles Bailey
True, but the way the question is asked it sounded, at least to me, the main issue was that `getline` was blocking while waiting on a newline character. The `peek` call would remedy that.
nathan
How would it remedy the problem? Even if your `dataAvailableInStream` doesn't block and doesn't return `... .eof()`, there's no guarantee that there's a `\n` somewhere in the available input characters. `std::getline` might still block. If there are no characters available your function might itself block which is another reason that it doesn't address the problem. Am I being really slow because obviously you have some upvotes; I just can't see how your function is supposed to help?
Charles Bailey
You're right, my function would only give the existence of data, but that was specifically what the author asked for "Do you know if exists a function for checking data availability before calling std::getline? I don't want to block." Once the function returned true, the author would then have to check if the available character is a newline, before calling getline. Should I add that portion to my answer, would that make it somewhat clearer?
nathan
Yes, but he explicitly states "I don't want to block"; that's his motivation for a checking function. If the checking function itself might block; doesn't that make it an inappropriate solution regardless?
Charles Bailey
I'm not sure he can get a whole solution using an iostream that blocks. From my brief scan of POCO::PipeInputStream it blocks on rdbuf() calls as well. I don't see the solution as inappropriate given the information in the question. That's why I asked the motivation for not blocking. I guess I'm the one being slow :).
nathan
Just because `std::istream` is a blocking interface doesn't mean that all functions block. For example, `std::streambuf::in_avail()` is non-blocking and could be used in a possible partial solution to the problem. Admittedly, it is not clear from POCO documentation whether the POCO BasicStreamBuf class has a conforming `showmanyc` override.
Charles Bailey
A: 

Although nathan's peek() answer will see if there is data, there is no guarantee that std::getline() will be successful in reading a "line".

It is always much easier albeit a bit backwards to try getline and check the result of thee function call itself:

std::string line;
while( !std::getline(std::cin, line) )
{
    cout << "Enter something please" << endl;
}

This code will run until cin receives something it likes (ie can extract and place in line). I don't see peek() being necessary or useful here.

EDIT: The thing is, cin (==standard keyboard input) will have to block the program as it waits for input, how else can it get any input when it wouldn't wait?

rubenvb
Good point about cin, I had not considered that it would block.
nathan
A: 

There is no standard way to verify if getline will block. You can use:

std::cin.rdbuf()->in_avail()

to see how many characters are definitely available before a read operation may block, but you would have to read the characters one by one before re-checking in_avail as there is no way to know in advance if any of the pending characters is a newline or the actual end of the stream. A getline call might block if this wasn't the case.

Note that although if in_avail() returns a postive number there are guaranteed that at least that many characters are available before the end of the stream, the converse is not true. If in_avail() returns zero there may still be characters available and the stream might not block immediately.

Charles Bailey
+1  A: 

The iostream library doesn't support the concept of non-blocking I/O. I don't think there's anything in the C++ standard that does. Any good solution would likely be platform-specific. If you can use the POSIX libraries, you might look into select. It's usually used for networking stuff, but it'll work just fine if you pass it the file descriptor for stdin.

Kristo
A: 

What problem are you trying to solve by avoiding the read blocking here?

Non-portably I imagine you could use poll or select to see if there's data to read on stdin (often fd 0 on unix systems).

Alternately you could create a second thread to do I/O and just let it block so you can continue normal processing in the main thread.

Mark B
if I use a second thread, for what I know there are issue in killing thread, so better to live it until the end of the application.Does this make sense?
Abruzzo Forte e Gentile