Once again: polling input in pure C++ question

Programming Topics (Computer Chess) and technical aspects as test techniques, book building, program tuning etc

Moderator: Andres Valverde

Once again: polling input in pure C++ question

Postby Vladimir Medvedev » 30 Jun 2006, 09:04

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;
}
User avatar
Vladimir Medvedev
 
Posts: 129
Joined: 29 Sep 2004, 10:03
Location: Moscow, Russia

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

Postby Bo Persson » 30 Jun 2006, 14:58

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.
Bo Persson
 
Posts: 5
Joined: 04 Aug 2005, 09:37
Location: Malmö, Sweden

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

Postby sje » 30 Jun 2006, 17:20

You want to use the select() function. It supports efficient waiting and it's portable.
sje
 
Posts: 10
Joined: 27 May 2006, 17:36

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

Postby Alvaro Begue » 05 Jul 2006, 21:11

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.
Alvaro Begue
 
Posts: 33
Joined: 03 Aug 2005, 23:48
Location: Stony Brook, New York, U.S.A.

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

Postby Vladimir Medvedev » 07 Jul 2006, 06:56

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 :(
User avatar
Vladimir Medvedev
 
Posts: 129
Joined: 29 Sep 2004, 10:03
Location: Moscow, Russia


Return to Programming and Technical Discussions

Who is online

Users browsing this forum: No registered users and 12 guests