Question

I need to add a timeout function for getchar() in my program.

What do I do so that when my program reaches the instruction getchar(), it will only wait for a certain amount of time for the user to make a keystroke and if the user does not make a keystroke within the given time limit, the program will "skip" the getchar()?

The operating system does not support the conio.h library so kbhit is not an option.

Was it helpful?

Solution

This is usually achieved by using select() on stdin. Another solution would be using alarm() and a dummy SIGALRM handler to interrupt the getchar() call (only working on POSIX systems though).

OTHER TIPS

How to add a timeout when reading from `stdin` I found this question is helpful.

Another method is using multithreading.

If you are using c++11, you can make use of condition_variable::wait_for() as a timer thread. And the original getchar() is blocking on another thread.

Here is an example:

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

When there is a keystroke, main thread will notify the worker thread.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top