c++nonblockinggetline

How can I use getline without blocking for input?


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.


Solution

  • 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().