3

I am writing a simple console application in LInux/C++ that accepts user input from command line. I am using std::getline( std::cin ) / std::cin >> text in a thread.

After 10 seconds I would like to stop accepting console input and write a text message then do other things. I am using a separate thread for the timer.

This approach doesn't work since I cannot check that 10 seconds have elapsed until the user has not inserted any text.

Is there any better way to stop the application accepting text and go to another piece of line? I was thinking to use settimer and signals programming but I would like something to call from a different thread for simplicity.

Regards

AFG

Abruzzo Forte e Gentile
  • 14,423
  • 28
  • 99
  • 173
  • 2
    Can you read the input in a new thread and then kill that thread from your main thread after 10 seconds have elapsed? – GWW Aug 10 '11 at 14:21
  • 1
    Apart from @GWW's suggestion, you can always use low-level OS facilities. In Linux/*nix, as I recall it's called "raw" i/o. But it's a long time since I did any of that. – Cheers and hth. - Alf Aug 10 '11 at 14:23

3 Answers3

6

You can use ncurses or if you don't want to, you can use select as described in this blog post. Basically, you can use select and specify the timeout. If the stdin FD is set, then you can read from it safely and won't block. If you want more info on select, check this out and of course Wikipedia. It's a handy call to know about. For example,

// if != 0, then there is data to be read on stdin

int kbhit()
{
    // timeout structure passed into select
    struct timeval tv;
    // fd_set passed into select
    fd_set fds;
    // Set up the timeout.  here we can wait for 1 second
    tv.tv_sec = 1;
    tv.tv_usec = 0;

    // Zero out the fd_set - make sure it's pristine
    FD_ZERO(&fds);
    // Set the FD that we want to read
    FD_SET(STDIN_FILENO, &fds); //STDIN_FILENO is 0
    // select takes the last file descriptor value + 1 in the fdset to check,
    // the fdset for reads, writes, and errors.  We are only passing in reads.
    // the last parameter is the timeout.  select will return if an FD is ready or 
    // the timeout has occurred
    select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
    // return 0 if STDIN is not ready to be read.
    return FD_ISSET(STDIN_FILENO, &fds);
}

See also this SO question on Peek stdin using pthreads

Community
  • 1
  • 1
  • Wow. It seems that I have interesting stuff to read. Thanks a lot. I wwill try the necurse cos seems being able also to do a lot of interesting things. I will let you know. – Abruzzo Forte e Gentile Aug 10 '11 at 15:04
  • Hi! I tested with a bit of delay. It works BUT it does need some code that CONSUMES the buffer after kbhit(). I replied with that below. Thanks a lot! – Abruzzo Forte e Gentile Aug 17 '11 at 16:37
2

A thread is overkill for this. In your input loop use select() to determine if stdin is ready for reading. You can check the time via a call to time() and exit the loop if 10 seconds have elapsed.

Jay
  • 13,803
  • 4
  • 42
  • 69
0

It works nice but a small piece of code is needed that 'consumes' the byte.

Below the usage of your kbhit():

 int main(int argc, const char** argv ){
     while( !kbhit() ){
        // do whatever you want here while
        // entering the text
        std::cout << "..while you write!" << std::endl;
     } // stops when you hit 'ENTER'
     std::string line;
     std::getline( std::cin, line ); // consume/stores into line
     // what was written until hitting 'ENTER'
 }
user229044
  • 232,980
  • 40
  • 330
  • 338
Abruzzo Forte e Gentile
  • 14,423
  • 28
  • 99
  • 173