2012-04-15 13 views
6

Cuando llama al expires_from_now() en un temporizador en ejecución, , se cancela el temporizador y se invoca un nuevo temporizador. Entonces se llama al controlador asociado. Es fácil discriminar en el controlador entre un temporizador cancelado y otro vencido. Sin embargo, me pregunto si existe una forma de discriminar entre un temporizador caducado y un temporizador reactivado. En ambos casos, el controlador se llama con error_code operation_aborted. O tal vez me faltan algunos detalles.Cómo discrimina un impulso cancelado de un impulso reactivado deadline_timer

El código siguiente genera el siguiente resultado:

20120415 21:32:28079507 Main: Timer1 set to 15 s.  
20120415 21:32:28079798 Main: Timer1 set to 12 s.  
20120415 21:32:28079916 Handler1: Timer 1 was cancelled or retriggered.  
20120415 21:32:40079860 Handler1: expired. 

Esto sugiere que el controlador no es capaz de poner en práctica acciones para un manejador cancelado, debido a retriggering un temporizador llamará el mismo controlador y con ello ejecutar el mismo comportamiento. Lo cual probablemente no sea el comportamiento previsto.

#include <boost/asio.hpp> 
#include <boost/thread.hpp> 
#include <boost/date_time/posix_time/posix_time.hpp> 
#include <boost/date_time/posix_time/posix_time_io.hpp> 
#include <iostream> 

using namespace boost::posix_time; 
using namespace std; 

void handler1(const boost::system::error_code &ec) 
{ 
    if (ec == boost::asio::error::operation_aborted) 
    { 
     cout << microsec_clock::local_time() << " Handler1: Timer was cancelled or retriggered." << endl; 
    } 
    else 
    { 
     cout << microsec_clock::local_time() << " Handler1: Timer expired." << endl; 
    } 
} 

boost::asio::io_service io_service1; 

void run1() 
{ 
    io_service1.run(); 
} 

int main() 
{ 
    time_facet *facet = new time_facet("%Y%m%d %H:%M:%S%f"); 
    cout.imbue(locale(cout.getloc(), facet)); 

    boost::asio::deadline_timer timer1(io_service1, seconds(15)); 
    timer1.async_wait(handler1); 
    cout << microsec_clock::local_time() << " Main: Timer1 set to 15 s." << endl; 
    // now actually run the timer 
    boost::thread thread1(run1); 
    timer1.expires_from_now(seconds(12)); 
    cout << microsec_clock::local_time() << " Main: Timer1 set to 12 s." << endl; 
    // here the timer is running, but we need to reset the deadline 
    timer1.async_wait(handler1); 
    thread1.join(); // wait for thread1 to terminate 
} 
+1

Por favor, dinos qué quieres lograr. ¿Cuál es la imagen más grande? –

+0

Estoy tratando de implementar algún retraso de activación desencadenado por eventos. Puedo implementar un retardo básico de encendido sin volver a dispararlo. Pero si acepta retrasos temporales variables o cambiantes, tendré que volver a dispararlo. –

+0

¿Y por qué no hacer nada, cuando se ejecuta operation_aborted, recuerde un controlador determinado y configúrelo de nuevo? –

Respuesta

4

Sugeriría crear una clase para envolver un deadline_timer usando la composición. Cuando lo cancele, configure una bandera para recordar que fue cancelado. En el controlador, restablece la bandera. Al invocar expires_from_now(), no establezca el indicador.

#include <boost/asio.hpp> 
#include <boost/thread.hpp> 
#include <boost/date_time/posix_time/posix_time.hpp> 
#include <boost/date_time/posix_time/posix_time_io.hpp> 
#include <iostream> 

class Timer 
{ 
public: 
    Timer(
      const std::string& name, 
      boost::asio::io_service& io_service 
     ) : 
     _name(name), 
     _timer(io_service), 
     _cancelled(false) 
    { 
     _timer.expires_from_now(boost::posix_time::seconds(0)); 
     this->wait(); 
    } 

    void wait() 
    { 
     _timer.async_wait(
       boost::bind(
        &Timer::handler, 
        this, 
        boost::asio::placeholders::error 
        ) 
       ); 
    } 

    void cancel() { 
     _cancelled = true; 
     _timer.cancel(); 
    } 

    void restart() { 
     _timer.expires_from_now(boost::posix_time::seconds(5)); 
    } 

private: 
    void handler(
      const boost::system::error_code& error 
      ) 
    { 
     if (!error) { 
      std::cout << _name << " " << __FUNCTION__ << std::endl; 
      _timer.expires_from_now(boost::posix_time::seconds(5)); 
      this->wait(); 
     } else if (error == boost::asio::error::operation_aborted && _cancelled) { 
      _cancelled = false; 
      std::cout << _name << " " << __FUNCTION__ << " cancelled" << std::endl; 
     } else if (error == boost::asio::error::operation_aborted) { 
      std::cout << _name << " " << __FUNCTION__ << " retriggered" << std::endl; 
      this->wait(); 
     } else { 
      std::cout << "other error: " << boost::system::system_error(error).what() << std::endl; 
     } 
    } 

private: 
    const std::string _name; 
    boost::asio::deadline_timer _timer; 
    bool _cancelled; 
}; 

int 
main() 
{ 
    boost::asio::io_service ios; 
    Timer timer1("timer1", ios); 
    Timer timer2("timer2", ios); 

    boost::thread thread(
      boost::bind(
       &boost::asio::io_service::run, 
       boost::ref(ios) 
       ) 
      ); 

    sleep(3); 
    std::cout << "cancelling" << std::endl; 
    timer1.cancel(); 
    timer2.restart(); 

    thread.join(); 
} 

sesión de ejemplo

macmini:stackoverflow samm$ ./a.out 
timer1 handler 
timer2 handler 
cancelling 
timer1 handler cancelled 
timer2 handler retriggered 
timer2 handler 
^C 
macmini:stackoverflow samm$ 
0

No sé de ninguna manera y, probablemente, no hay una buena manera de hacerlo (no hay nada en la documentación diciendo que se puede diferenciar estas dos situaciones).

Creo que esto fue hecho por propósito. Configuración deadline_timer a un nuevo tiempo de caducidad, cancells alguna controlador anterior, debido a que:

  • a veces es difícil saber si algo ya estaba esperando en el temporizador, por lo tanto, sería difícil saber qué es exactamente lo que va a pasar, cuando estableces un tiempo de vencimiento;
  • esta es una manera fácil de evitar que los eventos supervisados ​​se ejecuten dos veces, requiriendo manejar otro código de error de una manera especial es más propenso a errores.