dimanche 12 juin 2011

Asio et sockets - Un design alternatif

Jusqu'à présent, j'avais plutôt pris une route orientée objet, avec une session de base qui contient les appels socket asio dont il fallait dériver.

Cependant, je suis en train de me demander si une approche purement basée sur les callbacks pourrait donner de meilleurs résultats.

Je viens de commiter une classe très simple, dont on ne dérivera à priori pas, et dont voici la signature:


class SocketSession : public std::enable_shared_from_this<SocketSession>
{
public:
SocketSession(boost::asio::io_service & io_service);

void connect(const std::string & host,
int port,
const std::function<void()> & callback);

template<typename BODY>
void readMessage(const std::function<void(const std::shared_ptr<Header> &,
const std::shared_ptr<BODY> &)>
& callback);

template<typename BODY>
void sendMessage(const BODY & body);
}


Toutes les méthodes publiques sont thread safe, car appelant en interne les méthodes correspondantes à travers un strand. L'appelant, lui, se contente de passer les callbacks, lequels peuvent être également protégés par leur propre strand.

Avantages:
  • Le système est complètement thread safe

  • Pas besoin de locks, les appels sont tous protégés par le strand. C'est particulièrement utile pour l'envoi de messages, puisqu'il faut pousser les messages dans une queue afin de n'avoir qu'un seul appel à async_write

  • Contrairement à mon implémentation "dérivante", la partie socket pourra tourner de manière concurrente avec l'appelant, ce qui pourrait permettre une meilleure montée en charge (à vérifier, cependant). Tout du moins, en laissant à l'utilisateur de la classe le choix de protéger ses callbacks à travers un strand, on peut permettre une meilleure parallélisation lorsque c'est possible


L'inconvénient majeur est la multiplication des callbacks, et donc de copies et d'allocations.

Aucun commentaire: