简体   繁体   中英

How to make read() non-blocking and reset read()

So i made this function which acts like a countdown.I want to read a command while the countdown decreases. My big problem is making read() the wait for a input while countdown is decreasing.As you can see I tried using select() but after the first printf("timeout.\\n"); it stops trying to read. I made the show only once timeout or else it would go until countdown reached 0. I need to try read again.

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

EDIT: to use the fmod() function , I compile like this: gcc client.c -lm -o client.exe . I don`t think this is the problem but I am not sure.

select() modifies the fd_set upon exit to reflect which descriptors have been signaled. You are not resetting the fd_set after each timeout.

Also, on some platforms, select() modifies the timeval structure to reflect how much time is remaining, so you would have to reset the timeval each time you call select() on those platforms.

Also, your c variable is declared inside the loop and is uninitialized. Move it outside the loop instead.

Try something more like this:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM