using fgets as non-blocking function c++

2019-01-28 18:43发布

问题:

I'm writing a program that reads in a loop from the stdin, using the function fgets, as follows:

while(fgets(buffer2, BUFFERSIZE , stdin) != NULL){
  //Some code  
}

I want my code to be non-blocking, that is: I don't want the program to hold on the 'fgets' line when there's no input at the moment from the user.
How can i do it?

回答1:

fgets() is a blocking function, it is meant to wait until data is available.

If you want to perform asynchronous I/O, you can use select(), poll(), or epoll(). And then perform a read from the file descriptor when there is data available.

These functions use the file descriptor of the FILE* handle, retrieved by:

int fd = fileno(f);

If you are using Unix or Linux, then one solution can be to mark the file descriptor used by the file to be non-blocking. Example:

#include <fcntl.h>  
FILE *handle = popen("tail -f /als/als_test.txt", "r"); 
int fd = fileno(handle);  
flags = fcntl(fd, F_GETFL, 0); 
flags |= O_NONBLOCK; 
fcntl(fd, F_SETFL, flags); 

fgets should be non-blockng now and will return a null and set an error code for you.



回答2:

If you have a proper POSIX environment, you can use select() or poll() to check for input on stdin's descriptor before calling fgets()... read().

Jan's comment below (thanks!) explains why you can't use fgets() with this approach... summarily, there's an extra layer of buffering in the FILE object, and data can already be waiting in though the select() finds nothing more on the file descriptor... preventing your program from responding in a timely way, and potentially hanging if some other system is waiting for a response to already sent data before sending more on stdin.



回答3:

You basically have two options:

  1. Run that loop in a separate thread.
  2. Check if your OS supports some API for non-blocking IO.


回答4:

This would sound a little like overkill, but this is the one, that comes to my mind.

Use 2 different threads - one using this loop and waiting blocking ( I don't think that this could be done non-blocking). And when something is read, push it into a pipe.

Meanwhile, the other thread will do whatever it needs to do and check for data in the pipe from time to time ( apparently, you want this to be asynchronous, or at least I get it this way. If so, this means different threads )

But then, you'll need to synchronize the two threads very well. You should check your OS about multithreading and IO operations.



回答5:

On Linux, you can specify the end of input by pressing ctrl-d, and of-course you can do this using separate thread.