Boost asio - arrêt io_service

J'utilise boost::asio pour faire des paquets UDP de la collection. Le io_service objet est instancié dans un thread de travail, et io_service.run() est appelée à partir de l'intérieur de ce thread. Mon problème est d'obtenir io_service.run() pour retourner quand je suis en fait la collecte de paquets.

Je ne suis pas clair sur ce que les méthodes de io_service peut être appelé à d'autres threads lorsqu'il vient le temps d'arrêter mon thread de travail. J'ai une référence à la io_service objet, et à partir d'un autre thread, j'ai fais cet appel:

ios.dispatch( boost::bind( &udp_server::handle_kill, this ) );

Dans mon udp_server classe, le gestionnaire de cette fonction annule les travaux en cours à partir d'un seul boost::asio::ip::udp::socket et un seul boost::asio::deadline_timer objet. Les deux sont en attente d'une async travail à faire. À ce point, j'appelle ios.stop():

void udp_server::handle_kill()
{
    m_socket.cancel();
    m_timer.cancel();
    m_ios.stop();
}

Avec pas de travaux en attendant, je m'attends à ce moment-là que mon appel à l'ios.run() doit retourner - mais cela n'arrive pas.

Alors pourquoi n'est-il pas de retour? L'explication la plus probable pour moi, c'est que je ne devrais pas appeler io_service::dispatch() à partir d'un autre thread. Mais la méthode dispatch() sorte de semble comme il a été construit pour le faire - envoi d'un appel de fonction dans le thread qui io_service::run() est en train de travailler. Et il semble le faire.

Donc cela me laisse avec quelques questions connexes:

  1. Suis-je à l'aide de io_service::dispatch() correctement?
  2. Si toutes les tâches sont annulés, est-il une raison qui io_service::run() ne devrait pas revenir?
  3. socket::upd::cancel() ne semble pas être la bonne façon de fermer un socket et annuler tous les travaux. Quelle est la bonne façon?

asio fonctionne assez bien pour moi, mais j'ai besoin d'obtenir une meilleure compréhension de ce morceau de l'architecture.

Plus de données

socket::udp::cancel() n'est apparemment pas pris en charge l'opération sur un socket ouvert sous Win32 - si cette opération échoue par la levée d'une exception qui n'en fait provoquer une sortie de io_service::run(), mais certainement pas la sortie désirée.

socket::udp::close() ne semble pas annuler l'attente de l'async_receive_from() de la tâche, de sorte que l'appelant au lieu de socket::udp::cancel() semble laisser le fil quelque part à l'intérieur de io_service::run().

Est-il une raison pour laquelle vous envoi handle_kill à la io_service? Il devrait être sûr d'appeler handle_kill() dans ce thread. Si vous faites cela, faut-il encore accrocher dans run()?
c'est un thread de travail - il ne pas faire beaucoup de chose, mais lire des paquets. L'impulsion à tuer le thread de l'interface utilisateur, qui est dans un autre thread. Quelle que soit la méthode que j'utilise, il y a un thread-safe façon de communiquer avec le io_service::run() thread. Il me semble que io_service::dispatch() a été construit uniquement pour le besoin. Et handle_kill() ne semble pas être appelé dans le bon thread.
Vous devriez être en mesure d'arrêter la io_service à partir de n'importe quel thread, peu importe que ce soit un thread de travail pour io_service. Aussi, dispatch() et post() sont identiques, à l'exception que, si possible, dispatch() peut appeler la fonction inline immédiatement (si dispatch est appelée à partir d'une io_service thread). Donc, si vous savez pour un fait que votre dispatch() appel jamais sur un io_service fil, il est identique à post(). Cela ne résout pas votre problème. Est-il 10-15 ligne de code de l'échantillon que vous pouvez donner à qui reproduit le problème?
Je suis en train de travailler sur l'obtention d'un court exemple qui illustre cela. En attendant, je vois que l'appel ios::stop() à partir d'un autre thread ne fait en cause ios:run() pour sortir de la façon dont je le veux. J'ai été (et suis encore) hésitent à faire un appel de ce genre sur une méthode qui n'est pas explicitement appeler une garantie de threads comportement, mais il ne semble pas fonctionner. La question de savoir pourquoi mon appel indirect via dispatch() ne fonctionne pas, reste à être reproduit et compris.
veuillez accepter la réponse si c'est suffisant.

OriginalL'auteur Mark Nelson | 2011-01-26