Page 1 of 1

Once again: polling input in pure C++ question

PostPosted: 30 Jun 2006, 09:04
by Vladimir Medvedev
Here is a sample code which should count seconds of runtime, poll stdin from time to time, and do something when user hits the keyboard. It does not work. What is wrong in this code? How to fix it?

Yes, I know about IsPipe(), signal(), kbhit() and bla-bla-bla... (look GreKo's code, I have implemented polling input, and it works).

But is there more elegant, pure C++/stdlib solution of the problem?

Code: Select all
#include <iostream>
#include <vector>
using namespace std;

#include <time.h>

int main()
{
   cout.rdbuf()->pubsetbuf(NULL,0);
   cin.rdbuf()->pubsetbuf(NULL,0);

   time_t t0 = clock();
   long n1 = 0, n2 = 0;
   while(1)
   {
      n1++;
      if( n1 < 10000 )
         continue;

      if( cin.rdbuf()->in_avail() )
      {
         cout << "Input detected!" << endl;

         // Here we should process user input...
         // Unfortunately, this code never gets control :((
      }

      n1 = 0;
      if( clock() - t0 > 1000 )
      {
         n2++;
         cout << n2 << "\r";
         t0 = clock();
      }
   }
   return 0;
}

Re: Once again: polling input in pure C++ question

PostPosted: 30 Jun 2006, 14:58
by Bo Persson
Vladimir Medvedev wrote:Here is a sample code which should count seconds of runtime, poll stdin from time to time, and do something when user hits the keyboard. It does not work. What is wrong in this code? How to fix it?

Yes, I know about IsPipe(), signal(), kbhit() and bla-bla-bla... (look GreKo's code, I have implemented polling input, and it works).

But is there more elegant, pure C++/stdlib solution of the problem?

Code: Select all
#include <iostream>
#include <vector>
using namespace std;

#include <time.h>

int main()
{
   cout.rdbuf()->pubsetbuf(NULL,0);
   cin.rdbuf()->pubsetbuf(NULL,0);

   time_t t0 = clock();
   long n1 = 0, n2 = 0;
   while(1)
   {
      n1++;
      if( n1 < 10000 )
         continue;

      if( cin.rdbuf()->in_avail() )
      {
         cout << "Input detected!" << endl;

         // Here we should process user input...
         // Unfortunately, this code never gets control :((
      }

      n1 = 0;
      if( clock() - t0 > 1000 )
      {
         n2++;
         cout << n2 << "\r";
         t0 = clock();
      }
   }
   return 0;
}


Sorry, there is no perfect way of doing this. The function in_avail() returns the number of unread chars in the read buffer. And you just disabled buffering. :-)

You can either create a separate thread (non-standard :-) for the I/O, and keep a blocking read, or use the (non-standard) polling functions.

The standard library doesn't have any of those, as it would require every system to have a keyboard.

Re: Once again: polling input in pure C++ question

PostPosted: 30 Jun 2006, 17:20
by sje
You want to use the select() function. It supports efficient waiting and it's portable.

Re: Once again: polling input in pure C++ question

PostPosted: 05 Jul 2006, 21:11
by Alvaro Begue
What I ended up doing is having a header file utility.hpp that has declarations for all the system-dependent functions. Currently I just have two:

Code: Select all
#ifndef UTILITY_HPP_INCLUDED
#define UTILITY_HPP_INCLUDED

// This file contains the prototypes of functions
// that we are not implementing in standard C++.
// We will provide implementations for specific
// target platforms.

// This function returns immediately and tells us
// whether there is input to be read in stdin or not.
bool is_there_input();

// This returns the time in seconds, it doesn't really
// matter since when, since we are only going to use
// differences of values returned by it.
double now();

#endif


Then I have different .cpp files that implement them. For POSIX-compatible (i.e., almost anything other than Windows these days), I use utility_posix.cpp, which looks like this:
Code: Select all
#include "utility.hpp"

#include <iostream>
#include <sys/time.h>

bool is_there_input(){
  fd_set read,write,except;
  FD_ZERO(&read);
  FD_ZERO(&write);
  FD_ZERO(&except);
  FD_SET(0,&read); // stdin

  struct timeval timeout;
  timeout.tv_sec=0;
  timeout.tv_usec=0;

  return select(1,&read,&write,&except,&timeout);
}

double now(){
  struct timeval tv;
  gettimeofday(&tv,0);
  return tv.tv_sec+.000001*tv.tv_usec;
}



For Windows, I have utility_windows.cpp, which looks like this:
Code: Select all
#include "utility.hpp"
#include <windows.h>
#include <ctime>

bool is_there_input(){
  static DWORD available;
  available = 0;
  static HANDLE stdin_h = GetStdHandle(STD_INPUT_HANDLE);
  PeekNamedPipe(stdin_h, NULL, 0, 0, &available, 0);
  return available > 0;
}

double now(){
  return std::clock()/(double)CLOCKS_PER_SEC;
}


The now() function in this last file is perfectly standard. I made it system-dependent in case you have a more precise one available in your system (like the one in the POSIX version).

The is_there_input() I have for Windows only works on pipes, but I couldn't find a way of making it work for any stream, and UCI and Winboard use pipes to communicate.

I hope that helped. Oh, and feel free to use any of that code if you find it useful.

Re: Once again: polling input in pure C++ question

PostPosted: 07 Jul 2006, 06:56
by Vladimir Medvedev
sje wrote:You want to use the select() function. It supports efficient waiting and it's portable.


Unfortunatly it is not. Under Windows select() can't work with pipes :(