dimanche 21 septembre 2008

Asio et les timers - Une classe qui fait tout le boulot

J'avais précédemment causé des timers d'asio ici, mais vu que je viens de finir une importante sous-partie de mon sous-projet en cours (on a les jalons que l'on peut!), je vais m'étendre sur une petite classe outil qui m'a beaucoup simplifié la tâche.

Le code de la classe en question est un simple en-tête, disponible ici. L'idée est de dériver de la classe outil ainsi fournie en lui passant un paramètre template permettant de définir l'objet de callback, puis d'implémenter la méthode de callback. Voilà un programme minimaliste permettant d'utiliser ladite classe:


/* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details. */

// Timer.cpp

#include <set>
#include <asio/io_service.hpp>
#include <asio/placeholders.hpp>
#include <asio/deadline_timer.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/foreach.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>

#include "Timer.h"

class MyTimer : public Common::Timer<std::pair<int, std::string> >
{
public:
MyTimer(asio::io_service & io_service):
Common::Timer<std::pair<int, std::string> >(io_service)
{
add_async_event(boost::posix_time::milliseconds(500),
std::make_pair(500, "Every 500 ms"));
add_async_event(boost::posix_time::milliseconds(1300),
std::make_pair(1300, "Every 1300 ms"));
add_async_event(boost::posix_time::milliseconds(1400),
std::make_pair(1400, "Every 1400 ms"));
}

void onTimer(const std::pair<int, std::string> & data)
{
std::cout << data.second << std::endl;
add_async_event(boost::posix_time::milliseconds(data.first),
data);
}
};

int main()
{
asio::io_service io_service;
MyTimer myTimer(io_service);
io_service.run();
}


Certes, il y a beaucoup d'inclusions: elles ne sont pas avec le fichier d'en-tête parce que je me sers de la pré-compilation d'en-têtes, et que donc tous mes fichiers sources ont un #include "All.h" qui contient tout le monde. Mais venons-en au fait.

Je déclare donc ma classe MyTimer, qui dérive de ma classe utilitaire Timer à qui je passe, par exemple, une paire comprenant un entier et une chaîne. J'implémente onTimer prenant une référence sur ce même type, et basta!

En l'occurrence, j'enclenche trois évènements, que je répète quand ils arrivent à expiration dans ma classe.

Une petite compile plus tard...


g++ -o Timer Timer.cpp -lpthread


Et voilà le résultat:


Every 500 ms
Every 500 ms
Every 1300 ms
Every 1400 ms
Every 500 ms
Every 500 ms
Every 500 ms
Every 1300 ms
Every 1400 ms
Every 500 ms
Every 500 ms
Every 1300 ms


Ainsi, chaque classe peut gérer elle-même ses évènements asynchrones. Si par exemple le service est également utilisé pour des connexions réseau, l'on peut gérer ensemble à la fois les interactions venues de l'extérieur, et les minuteries internes.

Aucun commentaire: