2009-12-06 14 views
6

J'utilise des sockets synchrones asio pour lire des données sur TCP à partir d'un thread d'arrière-plan. Ceci est encapsulé dans une classe "serveur". Cependant, je souhaite que le thread se termine lorsque le destructeur de cette classe est appelé. Le problème est qu'un appel à l'une des fonctions de lecture se bloque, de sorte que le thread ne peut pas être facilement terminé. Dans Win32 il y a une API pour cela: WaitForMultipleObjects qui ferait exactement ce que je veux.Interruption boost :: asio lecture synchrone?

Comment pourrais-je obtenir un effet similaire avec boost?

Répondre

2

Dans notre application, nous définissons la condition de «terminaison», puis utilisons une connexion automatique au port sur lequel le thread écoute afin qu'il se réveille, note la condition de fin et se termine. Vous pouvez également vérifier l'implémentation de boost - s'ils ne font que lire en clair sur le socket (c'est-à-dire ne pas utiliser eux-mêmes WaitForMultipleObjects en interne) alors vous pouvez probablement conclure qu'il n'y a rien à débloquer simplement et proprement le fil. S'ils attendent sur plusieurs objets (ou un port d'achèvement), vous pouvez creuser pour voir si la capacité de réveiller le thread bloquant est exposée à l'extérieur. Enfin, vous pourriez tuer le thread - mais vous devrez sortir du boost pour le faire, et comprendre les conséquences, telles que des ressources qui pendent ou qui fuient. Si vous fermez la session, cela peut ne pas poser problème, en fonction de ce que ce thread faisait d'autre.

2

Je n'ai trouvé aucun moyen facile de le faire. Supposément, il existe des moyens d'annuler Win32 IOCP, mais cela ne fonctionne pas bien sur Windows XP. MS l'a corrigé pour Windows Vista et 7. L'approche recommandée pour annuler asio async_read ou async_write est de fermer le socket.

  • [destructor] noter que nous voulons TearDown
  • [destructor] fermer la prise
  • [destructor] attendre des gestionnaires d'achèvement

  • [d'achèvement] si démolissant et nous vient d'échouer parce que le socket s'est fermé, informez le destructeur que les gestionnaires d'achèvement sont terminés.

  • [achèvement] retourner immédiatement.

Faites attention si vous choisissez de l'implémenter. Fermeture de la socket est assez simple. 'attendre les gestionnaires de complétion' est cependant un euphémisme énorme. Il existe plusieurs cas de coin subtils et conditions de concurrence qui peuvent se produire lorsque le thread du serveur et son destructeur interagissent.

C'était assez subtile que nous construisons une enveloppe d'achèvement (similaire à io_service::strand juste pour gérer l'annulation de manière synchrone tous les rappels d'achèvement en cours.

1

La meilleure façon est de créer un socketpair(), (tout ce qui est en boost::asio le langage), ajouter le lecteur finit à la boucle d'événement, puis ferme l'écrivain à la fin.Vous serez réveillé immédiatement avec un événement eof sur cette prise

Le fil doit alors se fermer volontairement.

Le géniteur du fil devrait dans sa destructor, disposer des éléments suivants:

~object() 
{ 
    shutdown_queue.shutdown(); // ask thread to shut down 
    thread.join();    // wait until it does 
} 
-1

utilisation socket.cancel(); pour mettre fin à toutes les opérations asynchrones en cours bloquant un socket. Les sockets client peuvent avoir besoin d'être détruits en boucle. Je n'ai jamais eu à fermer le serveur de cette façon, mais vous pouvez utiliser shared_from_this() et exécuter cancel()/close() dans une boucle similaire à l'exemple async_writes du chat boost pour tous les clients.

Questions connexes