Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add a Timeout for getchar()

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.

like image 968
brain56 Avatar asked Mar 16 '11 07:03

brain56


People also ask

What can I use instead of Getchar?

You can also use getc(stdin) instead of getchar() in the for statement to get a line of input from stdin .

What is the format specifier for getchar ()?

In C programming, we use scanf() for formatted input, and printf() for formatted output, gets() or getchar() for unformatted input, and puts() or putchar() for unformatted output.

How many characters does function getchar () read?

getchar may return any of the 256 possible characters, and it also may return EOF to indicate end-of-file, for a total of 257 different possible return values.

Is Getchar safe in C?

getchar() is a standard C function and is a safe function. you may come across non-standard function getch() or getche() if you are learning from multiple sources. Don't use them in your code.


2 Answers

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).

like image 87
ThiefMaster Avatar answered Sep 23 '22 00:09

ThiefMaster


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.

like image 41
shiqi Avatar answered Sep 23 '22 00:09

shiqi