【问题标题】:How to start counting 5 seconds before exiting from program?如何在退出程序前开始计数 5 秒?
【发布时间】:2018-08-21 22:03:39
【问题描述】:

我已经为此烦恼了好几个小时了。基本上,我有一个程序要求用户输入他的密码 (123),如果用户在 5 秒 内没有输入任何内容,那么程序将退出(游戏结束)。我一直在尝试使用 time(NULL) 和 clock() 但仍然没有运气。谁能指出我正确的方向,好吗?提前非常感谢!

这是我的代码:

#include <stdio.h>
#include <time.h>

 int main(){
   int password = 0;
   int num = 0;
   printf("%s\n", "Please enter your password");
   scanf("%d", &password);
   // Here I need to check if user didnt enter anything for 5 seconds,
   // and if he didnt enter anything then exit out of the program
   // I tried using time
   // time_t start = time(NULL);
   // time_t stop = time(NULL);
   //   if(((stop - start) * 1000) > 5000){
   //  printf("%s\n", "Game Over");
   //  break;          
  //  }

   printf("%s\n", "Thank you for entering your password, now enter any number");
   scanf("%d", &num);
   return 0;
 }

【问题讨论】:

  • 我的 2 美分是这个任务需要进程或线程
  • 不要使用break作为初学者使用return 0scanf也是一个阻塞调用,你需要使用fork或类似的东西来完成你想要的
  • @snr线程如何实现?
  • @Mitchel0022 在使用 return 0 后如何让它工作并在 5 秒后退出程序,如果用户没有输入任何内容?
  • 启动一个休眠 5 秒的 pthread 然后检查原子的“用户输入的内容”标志并在未设置时终止进程是相当简单的。这样做比使用 select() 更容易。

标签: c


【解决方案1】:

您的主要挑战是scanf() - 以及getchar() 和类似的命令 - 是阻塞。在用户实际输入任何输入之前,可能会经过一段未知的时间间隔 - 而您的 5 秒可能已经到了那个阶段。

select() - 超时监控文件描述符

我认为最可行的选项之一是使用select() - 它监视某些文件描述符集的活动。具体来说,您希望监视 stdin 文件描述符上的活动。

我认为以下内容接近您所需要的。

#include <stdio.h>
#include <sys/select.h>
#include <termios.h>
#include <time.h>
#include <unistd.h>

int main(void) {
    char buf[16] = {'\0'};
    char *pass = buf;
    time_t time_update = 0, time_now = 0;
    struct timeval tm;
    int res = 0;
    struct termios term_attr, new_attr;
    fd_set rset;

    // Change terminal attributes (We don't want line-buffered mode.)
    tcgetattr(fileno(stdin), &term_attr);
    tcgetattr(fileno(stdin), &new_attr);
    new_attr.c_lflag &= ~(ICANON | ECHO);

    tcsetattr(fileno(stdin), TCSANOW, &new_attr);

    printf("Enter password: ");

    time_update = time(NULL);
    while (1) {
        tm.tv_sec = 0;
        tm.tv_usec = 50000;
        FD_ZERO(&rset);
        FD_SET(STDIN_FILENO, &rset);

        res = select(fileno(stdin) + 1, &rset, NULL, NULL, &tm);
        if (FD_ISSET(STDIN_FILENO, &rset)) {
            time_update = time(NULL);
            int c = getchar();
            if (c == '\n') {
                break;
            }
            *pass = c;
            pass++;
        }
        time_now = time(NULL);
        if (time_now - time_update >= 5) {
            puts("Timed out ...");
            break;
        }
    }

    pass = buf;

    printf("You entered: %s \n", pass);

    // Restore original terminal attributes
    tcsetattr(fileno(stdin), TCSANOW, &term_attr);

    return 0;
}

注意事项

  • select() 的最后一个参数是struct timeval,它指定等待指定文件描述符上的活动的时间。在本例中,我指定了 50 毫秒的超时时间。
  • 终端需要置于字符缓冲模式而不是行缓冲模式。 (否则每次有新字符时您都需要按 Enter。)

操作系统支持

select() 是 POSIX 规范的一部分,但我不知道它是否在 Windows 上实现。也许有人可以澄清一下?

另外......我不知道设置终端属性是否会在 Windows 上按预期工作。 (我只在 Linux 上测试过。)

我意识到这个解决方案可能比您希望的更长/更复杂 - 但我不知道更简单的方法。

【讨论】:

    猜你喜欢
    • 2012-10-17
    • 2013-03-22
    • 2021-10-22
    • 1970-01-01
    • 2014-02-05
    • 1970-01-01
    • 1970-01-01
    • 2012-12-11
    • 1970-01-01
    相关资源
    最近更新 更多