c - 如何使 read() 非阻塞并重置 read()

标签 c select

所以我做了这个功能,就像倒计时一样。我想在倒计时减少时读取命令。我的大问题是让 read() 在倒计时减少时等待输入。如您所见,我尝试使用 select() 但在第一个 printf 之后("timeout.\n"); 它停止尝试读取。我只制作了一次超时,否则它会持续到倒计时达到 0。我需要再次尝试阅读。

int timer(int seconds) 
{
    time_t start, end;
    double elapsed;
    int opened=0; 
    char command[10];
    struct timeval tv;
    int fd_stdin,rv;
    fd_set rd;

    fd_stdin=fileno(stdin);

    FD_ZERO(&rd);
    FD_SET(fileno(stdin),&rd);

    tv.tv_sec=5;
    tv.tv_usec=0;

    time(&start);  /* start the timer */

    do
    {
        time(&end);

        elapsed = difftime(end, start);

        if(fmod(elapsed,5)==0)
        {
            printf("Time remaining: %f minutes.\n", (seconds-elapsed)/60);
            sleep(1);
            if(opened==0)
            {
                printf("Use opentest to open your test.\n");
                opened=1;
            }
            fflush(stdout);
        }
        int c;
        rv=select(fd_stdin+1,&rd,NULL,NULL,&tv);
        if(rv==-1)
        {
            perror("Error on select.\n");
            exit(1);
        }
        else if (rv==0 && c!=1)
        {
            printf("timeout.\n");
            rv=select(fd_stdin+1,&rd,NULL,NULL,&tv);
            c=1;
        }
        else 
        {
            c=0;
            read(fd_stdin,command,10);
        }
    }
    while(elapsed < seconds);
    return 0;
}

编辑:为了使用fmod() 函数,我这样编译:gcc client.c -lm -o client.exe。我不认为这是问题所在,但我不确定。

最佳答案

select() 在退出时修改 fd_set 以反射(reflect)哪些描述符已发出信号。您没有在每次超时后重置 fd_set

此外,在某些平台上,select() 会修改 timeval 结构以反射(reflect)剩余时间,因此您必须重置 timeval 每次在这些平台上调用 select() 时。

此外,您的 c 变量在循环内声明并且未初始化。而是将其移出循环。

尝试更像这样的东西:

int timer(int seconds) 
{
    time_t start, end;
    double elapsed;
    int opened = 0; 
    char command[10];
    struct timeval tv;
    int fd_stdin, rv;
    fd_set rd;
    int c = 0;

    fd_stdin = fileno(stdin);

    time(&start);  /* start the timer */

    do
    {
        time(&end);

        elapsed = difftime(end, start);

        if (fmod(elapsed, 5) == 0)
        {
            printf("Time remaining: %f minutes.\n", (seconds-elapsed)/60);
            sleep(1);
            if (opened == 0)
            {
                printf("Use opentest to open your test.\n");
                opened = 1;
            }
            fflush(stdout);
        }

        FD_ZERO(&rd);
        FD_SET(fd_stdin, &rd);

        tv.tv_sec = 5;
        tv.tv_usec = 0;

        rv = select(fd_stdin+1, &rd, NULL, NULL, &tv);
        if (rv == -1)
        {
            perror("Error on select.\n");
            exit(1);
        }
        else if (rv == 0)
        {
            if (c != 1)
            {
                printf("timeout.\n");
                c = 1;
            }
        }
        else 
        {
            c = 0;
            read(fd_stdin, command, 10);
        }
    }
    while (elapsed < seconds);
    return 0;
}

关于c - 如何使 read() 非阻塞并重置 read(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34688073/

相关文章:

MySQL : How to SELECT DISTINCT from multiple databases

c - C 中的链表操作(段错误核心转储!)

jQuery 选择 "change"事件未触发

javascript - 如何自定义<select>显示值?

PHP MySQL 选择日期时间值在过去 n 分钟内的行

javascript - 填充数据库时禁用按钮在 javascript 上为 null 时启用

c - C中的printf函数如何获取可变参数列表中每个参数的大小?

c - 指向结构和打印的指针

c - 数据结构中灵活的可变长度

c - 使用结构内的字符串进行选择排序