tags:

views:

90

answers:

3

Is there a way to timeout a reading from stdin in order for the program not to hang for too long ?

read(0, var, numberofbytes);
+7  A: 

You can use ncurses or if you don't want to, you can use select as described in this blog post. Basically, you can use select and specify the timeout. If the stdin FD is set, then you can read from it safely and won't block. If you want more info on select, check this out and of course wikipedia. It's a handy call to know about.

EDIT: I feel compelled to supply code, so here it is, straight from the blog post with some comments.

// if != 0, then there is data to be read on stdin
int kbhit()
{
    // timeout structure passed into select
    struct timeval tv;
    // fd_set passed into select
    fd_set fds;
    // Set up the timeout.  here we can wait for 1 second
    tv.tv_sec = 1;
    tv.tv_usec = 0;

    // Zero out the fd_set - make sure it's pristine
    FD_ZERO(&fds);
    // Set the FD that we want to read
    FD_SET(STDIN_FILENO, &fds); //STDIN_FILENO is 0
    // select takes the last file descriptor value + 1 in the fdset to check,
    // the fdset for reads, writes, and errors.  We are only passing in reads.
    // the last parameter is the timeout.  select will return if an FD is ready or 
    // the timeout has occurred
    select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
    // return 0 if STDIN is not ready to be read.
    return FD_ISSET(STDIN_FILENO, &fds);
}
SB
+1 Nice blog post.
Tom
A: 

Call alarm() or ualarm() before calling read(). This will cause a SIGALRM signal to be delivered to the process, interrupting the read(), provided that you haven't told the O/S to restart system calls after interrupts. Be sure to cancel the alarm if the read() returns normally.

Steve Emmerson
Default hangler for `SIGALRM` terminates the process, so you'll need to install a signal handler. And on a sane OS, signals do not interrupt syscalls by default, so you'll need to use `sigaction` instead of `signal` to ensure that they do.
R..
+4  A: 

Use select, poll or any other IO multiplexing facility. They all take a timeout argument. Note that this will not work if stdin is a regular file, but it will if stdin is a terminal/tty,socket,pipe.

e.g.

fd_set selectset;
struct timeval timeout = {10,0}; //timeout of 10 secs.
int ret;
FD_ZERO(&selectset);
FD_SET(0,&selectset);
ret =  select(1,&selectset,NULL,NULL,&timeout);
if(ret == 0)
  //timeout
else if(ret == -1)
  //error
else 
   // stdin has data, read it
   // (we know stdin is readable, since we only asked for read events
   //and stdin is the only fd in our select set.
nos
+1 for answer that does not depend on signals and messing with the process's global state, which may not be appropriate/allowable from library code.
R..
Well, it will "work" for a regular file, inasmuch as it will always say that reading from it will not block, which is true (waiting for a disk or network filesystem to supply data isn't counted as "blocking").
caf
Right, it isn't counted as blocking, yet it can block for a considerable time.
nos
+1 Thank you for specifying an error handling procedure as the programmer may choose to handle a timeout differently from an error.
bobby