Is there any method to call getline()
and, if there is no input given, not to block and waiting?
I have the following code:
while(true){
if(recv(sd, tBuffer, sizeof(tBuffer), MSG_PEEK | MSG_DONTWAIT) > 0) break;
getline(cin,send);
}
I want to wait for an input, but if I receive some data at sd
socket, I want stop waiting for the data and exit the while
. My code right now, just stucks on first iteration at getline()
. I want to evaluate getline()
, and if is no input available, go back at if
.
Is this possible?
PS: I tried with cin.peek()
, but that blocks for input too.
You should be able to do this by setting non-blocking mode on standard input, file descriptor 0:
int flags = fcntl(0, F_GETFL, 0);
fcntl(0, F_SETFL, flags | O_NONBLOCK);
Now, if there's no input available, the underlying read()
system call will return 0, and std::cin
will think that this is end of file, and set eof()
on std::cin
.
When you wish to read from standard input again, just clear()
the stream's state.
The only complicating factor here is that this makes it difficult to detect a real end-of-file condition on std::cin
. Not much a problem when standard input is an interactive terminal; but if standard input can be a file this is going to be an issue.
In that case, your only realistic option is to forego std::cin
completely, put non-blocking mode on file descriptor 0, poll()
or select()
it, to determine when there's something to read, then read()
it.
Although you could also use poll()
or select()
with std::cin
, this is going to get complicated, because you will need to explicitly check if there's anything already buffered in std::cin
's streambuf
, because that would, obviously, preempt any kind of poll()
or select()
checking; but by attempting to read something from std::cin
, you still run the risk of reading the buffered data, then attempting to read()
from the underlying file descriptor that's now in non-blocking mode, this resulting in a fake end-of-file condition.
To summarize: you need invest some additional time reading and understanding how file streams, and stream buffers work; and how file descriptors actually work, and how non-blocking mode works; in order to figure out the correct logic you will need to use.
Oh, and if you insist on going the non-blocking route with std::cin
, and getline()
, you will have no easy way to determine if the string returned by getline()
ends because getline()
actually read a newline from standard input, or it reached a premature fake-end of file condition and not the entire line of input has actually been read.
So, with non-blocking mode, and std::cin
, you'll be pretty much forced to use read()
, instead of getline()
.
The istream::getsome() method can be used to perform non-blocking reads. You can use it to build a non-blocking equivalent of std::getline.
bool getline_async(std::istream& is, std::string& str, char delim = '\n') {
static std::string lineSoFar;
char inChar;
int charsRead = 0;
bool lineRead = false;
str = "";
do {
charsRead = is.readsome(&inChar, 1);
if (charsRead == 1) {
// if the delimiter is read then return the string so far
if (inChar == delim) {
str = lineSoFar;
lineSoFar = "";
lineRead = true;
} else { // otherwise add it to the string so far
lineSoFar.append(1, inChar);
}
}
} while (charsRead != 0 && !lineRead);
return lineRead;
}
This functions works identically to the original std::getline()
function except it always returns instantly. I've got it on my gists because it comes in handy occasionally.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With