问题 设置读取标准输入的超时时间


有没有办法超时stdin读取,以免程序挂起太长时间?

read(0, var, numberofbytes);

10846
2017-09-14 18:31


起源



答案:


您可以使用 ncurses的 或者如果你不想,你可以使用如此描述的选择 博客文章。基本上,你可以使用 select 并指定超时。如果设置了stdin FD,那么您可以安全地读取它并且不会阻塞。如果您想要选择更多信息,请检查 这个 出去当然 维基百科。知道这是一个方便的电话。

编辑: 我觉得有必要提供代码,所以在这里,直接从博客文章中提供一些评论。

// 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);
}

10
2017-09-14 18:43



+1好博客文章。 - Tom


答案:


您可以使用 ncurses的 或者如果你不想,你可以使用如此描述的选择 博客文章。基本上,你可以使用 select 并指定超时。如果设置了stdin FD,那么您可以安全地读取它并且不会阻塞。如果您想要选择更多信息,请检查 这个 出去当然 维基百科。知道这是一个方便的电话。

编辑: 我觉得有必要提供代码,所以在这里,直接从博客文章中提供一些评论。

// 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);
}

10
2017-09-14 18:43



+1好博客文章。 - Tom


使用select,poll或任何其他IO多路复用工具。他们都采取超时论证。 请注意,如果stdin是常规文件,这将不起作用,但如果stdin是终端/ tty,套接字,管道,它将会起作用。

例如

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.

6
2017-09-14 19:24



+1答案不依赖于信号和处理进程的全局状态,这可能不适合/允许从库代码中获取。 - R..
好吧,它将“正常”用于常规文件,因为它总是会说从它读取不会阻塞,这是真的(等待磁盘或网络文件系统提供数据不算作“阻塞”)。 - caf
是的,它不算是阻塞,但它可以阻止相当长的一段时间。 - nos
+1感谢您指定错误处理过程,因为程序员可能会选择以不同于错误的方式处理超时。 - Neeladri Vishweswaran


呼叫 alarm() 要么 ualarm() 在打电话之前 read()。这将导致一个 SIGALRM 信号传递给进程,中断read(), 提供 你没有告诉操作系统在中断后重启系统调用。如果是,请务必取消警报 read() 正常返回。


0
2017-09-14 19:08



默认的挂载器 SIGALRM 终止进程,因此您需要安装信号处理程序。在一个理智的操作系统上,默认情况下信号不会中断系统调用,因此您需要使用 sigaction 代替 signal 确保他们这样做。 - R..