Temporizadores

Iniciado por Juan821, 9 Julio 2014, 03:56 AM

0 Miembros y 1 Visitante están viendo este tema.

eferion

No es un mecanismo excesivamente depurado pero sirve para la ocasión:

Lo primero que necesitamos es una clase que nos permita "controlar" la entrada del teclado.

Para nuestra desgracia, el estándar de C++ no ayuda, ya que los mecanismos de entrada no van a devolver ningún dato hasta que el usuario presione la tecla "enter". Por este motivo nos tenemos que pegar con mecanismos menos portables... para la ocasión he usado la tan odiada "conio". Si alguien se lo quiere currar más está en su perfecto derecho.

El método run de la clase es bastante simple... cuando se presiona una tecla, activa un flag que indica la intención del usuario de introducir un número... cuando se introduce un carácter se actualiza el número introducido (esta versión no admite backspace)... cuando se introduce un enter se almacena el número y se sale de la función.

Código (cpp) [Seleccionar]

class DataManager
{
 public:

   DataManager( ) = default;

   DataManager( const DataManager& ) = delete;

   ~DataManager( ) = default;

   void Run( )
   {
     int temp_number = 0;

     while ( true )
     {
       char c = getch( );
       _withData = true;

       if ( c != '\n' && c != '\r' )
       {
         std::cout << c;
         temp_number *= 10;
         temp_number += c - '0';
       }
       else
       {
         std::cout << std::endl;
         _number = temp_number;
         break;
       }
     }
   }

   bool WithData( ) const
   { return _withData; }

   int Number( ) const
   { return _number; }

   const DataManager& operator=( const DataManager& ) = delete;

 private:

   bool _withData = false;
   int _number = 0;
};


Después necesitamos una clase para llevar de forma sencilla el conteo del tiempo... algo del tipo:

Código (cpp) [Seleccionar]

class Timer
{
 public:
   using milliseconds = std::chrono::milliseconds;

   Timer( )
   {
     Reset( );
   }

   Timer( const Timer& ) = delete;

   ~Timer( ) = default;

   void Reset( )
   {
     _start = std::chrono::high_resolution_clock::now( );
   }

   milliseconds Elapsed( ) const
   {
     return std::chrono::duration_cast< milliseconds >( std::chrono::high_resolution_clock::now( ) - _start );
   }

   const Timer& operator=( const Timer& ) = delete;

 private:
   std::chrono::high_resolution_clock::time_point _start;
};


Cuando se crea la clase se registra el tiempo y llamando a "Elapsed" se devuelve el número de milisegundos desde ese instante. Reset vuelve a inicializar la clase.

Con estos ingredientes ya tenemos casi todo el trabajo echo... solo nos falta mezclarlos convenientemente en el main:

Código (cpp) [Seleccionar]

int main( )
{
 std::cout << "Introduce un numero." << std::endl;
 std::cout << "Tienes 5 segundos para empezar" << std::endl;

 DataManager manager;

 std::thread thread{ [](DataManager* mgr){ mgr->Run( ); }, &manager };

 Timer timer;
 while ( timer.Elapsed( ) < std::chrono::seconds{ 5 } )
 {
   if ( manager.WithData( ) )
     break;
 }

 if ( !manager.WithData( ) )
   thread.detach( );
 else
   thread.join( );

 if ( manager.WithData( ) )
   std::cout << "Has introducido el numero: " << manager.Number( ) << std::endl;
 else
   std::cout << "No has introducido ningun numero." << std::endl;
}


Para controlar la entrada del teclado se crea un hilo. Después se inicializa el temporizador y se mantiene una espera activa de 5 segundos. La idea del temporizador en vez de un sleep es para que la aplicación pueda responder instantáneamente si el usuario introduce el número antes de 5 segundos.

Pasado el tiempo de espera activa se comprueba si el usuario ha hecho al menos el amago de introducir un número... si es así entonces espera pacientemente a que el usuario termine de introducir el número... en caso contrario finaliza el hilo y muestra el mensaje correspondiente.

Como he comentado antes, es algo muy mejorable. El ejemplo lo he realizado a petición de vangodp y sirve solo con fines ilustrativos.

PD.: utiliza funciones propias de C++11, ojo con los compiladores no compatibles.

leosansan

#11
Sin conio.h pero con:

Código (cpp) [Seleccionar]
#include <windows.h>
#include <iostream>
#include <iomanip>
#include <unistd.h>
#include <pthread.h>


Creo un hilo para el contador, que sigo usando Sleep por ganseria en lugar de cronos, y poco más. Sólo que el "Quedan" podemos evitarlo ya que distorsiona un poco la impresión. Pero bueno, como intento sin usar conio y que no espere hasta que se dé al ENTER creo que vale.....y ojo que no soy especialista en hilos, así que las críticas suaves, please  ;)

Código (cpp) [Seleccionar]

using namespace std;

void *hilo1(void *X){
 int i , ss = 10 ;
 cout << "Creando hilo " << endl;
 while( 1 ){
   for( i = ss ; i>= 0 ; i-=2 ){
     Sleep(2000);
   cout << "   Quedan: " << setw(2) << i << " segundos.\r"  ;
   }
   if ( i == -1 ) break;
 }
 cout << endl << "Tiempo excedido\n" << endl;
 exit(1) ;
}

int main(){
 int  algo = 0 ;
 pthread_t hilo ;
 pthread_create (& hilo , NULL , hilo1 , NULL );
 cout << endl << "No te olvides del ENTER " << endl;
 cin >> algo ;
 cout << endl << endl << "algo = " << algo << endl;
 return 0;
}


¡¡¡¡ Saluditos! ..... !!!!