为 getchar() 添加超时

问题描述 投票:0回答:3

我需要在程序中为 getchar() 添加超时函数。

我该怎么做才能让我的程序到达 getchar() 指令时,只等待一定的时间让用户敲击键盘,如果用户在给定的时间内没有敲击键盘,程序会“跳过”getchar()?

操作系统不支持 conio.h 库,因此 kbhit 不是一个选项。

c time input timeout getchar
3个回答
7
投票

这通常是通过在

select()
上使用
stdin
来实现的。另一种解决方案是使用
alarm()
和虚拟 SIGALRM 处理程序来中断
getchar()
调用(但仅适用于 POSIX 系统)。


1
投票

如何在从`stdin`读取时添加超时 我发现这个问题很有帮助。

另一种方法是使用多线程。

如果您使用的是 c++11,则可以使用

condition_variable::wait_for()
作为计时器线程。原来的 getchar() 在另一个线程上阻塞。

这是一个例子:

#include <termios.h>
#include <unistd.h>
#include <thread>
#include <chrono>
#include <iostream>

std::mutex mtx;
std::condition_variable cv;

int ch;
bool INPUT_SIGNAL = false;

void getch ( void ) {
  struct termios oldt, newt;

  tcgetattr ( STDIN_FILENO, &oldt );
  newt = oldt;
  newt.c_lflag &= ~( ICANON | ECHO );

  tcsetattr ( STDIN_FILENO, TCSANOW, &newt );
  ch = getchar();
  tcsetattr ( STDIN_FILENO, TCSANOW, &oldt );

  INPUT_SIGNAL = true;  

  cv.notify_one();
}

void timer ( int period ) {
    for(;;) {
        std::unique_lock<std::mutex> lck(mtx);

        cv.wait_for(lck, std::chrono::seconds(period), []{return INPUT_SIGNAL;});   

        if(INPUT_SIGNAL) {
            INPUT_SIGNAL = false;
            std::cout << ch << "\n";
        } else {
            std::cout << 0 << "\n";
        }
    }
}

int main() {
    std::thread worker(timer, 1);
    for(;;) {
        getch();
    }
    worker.join();
    return 0;
}

当有按键时,主线程会通知工作线程。


0
投票

这个问题很老了,但我仍然回答它,希望它可以帮助像我这样的人。该解决方案适用于 Linux - 无需使用线程/计时器。您可以使用

tcgetattr
tcsetattr
获取和设置
STDIN_FILENO
的终端设置。这些设置允许您配置超时(VTIME,它指定非规范读取的超时(以十秒为单位))(查看详细信息)。

#include <termios.h>
#include <cstdio>
#include <unistd.h>
#include <cstring>
#include <iostream>

char ch {};
termios originalTermios {};
termios newTermios {};

void setTerminalSettings()
{
    // Save the current terminal settings
    if (tcgetattr(STDIN_FILENO, &originalTermios) == -1)
    {
        std::cerr << "tcgetattr: " << std::strerror(errno) << "\n";
        return;
    }

    // New terminal settings
    newTermios = originalTermios;
    newTermios.c_lflag &= ~(ICANON | ECHO); // Disable canonical mode and echoing

    newTermios.c_cc[VTIME] = 50; // 5 sec
    newTermios.c_cc[VMIN] = 0; // No wait condition for min byte read

    // Set the new terminal settings
    if (tcsetattr(STDIN_FILENO, TCSANOW, &newTermios) == -1)
    {
        std::cerr << "tcsetattr: " << std::strerror(errno) << "\n";
    }
}

int main() {
    setTerminalSettings();
    ssize_t bytesRead = read(STDIN_FILENO, &ch, 1);
    if (bytesRead > 0)
    {
        std::cout << "you typed " << ch;
    }
    else
    {
        std::cout << "time out";
    }

    // reset
    tcsetattr(STDIN_FILENO, TCSANOW, &originalTermios);
    return 0;
}

我试图让它与

getchar()
一起工作,但由于某种原因,它在第一次超时后不起作用。不过,我希望这种阅读方法仍然足够好。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.