10
votes

BOOST ASIO ASYNCHRONUSE EN ATTENTION D'UNE Variable de condition

est-il possible d'effectuer une attente asynchrone (lecture: non bloquante) sur une variable conditionnelle à Boost :: Asio? S'il n'est pas directement soutenu des indications sur la mise en œuvre, elle serait appréciée.

Je pourrais mettre en œuvre une minuterie et tirer un réveil, même tous les quelques ms, mais c'est une approche très inférieure, j'ai du mal à croire que la synchronisation variable de condition n'est pas mise en œuvre / documentée.


3 Réponses :


7
votes

Si je comprends bien l'intention correctement, vous souhaitez lancer un gestionnaire d'événements, lorsque la variable de condition est signalée, dans le contexte de la piscine de fil ASIO? Je pense qu'il serait suffisant d'attendre sur la variable de condition au début du gestionnaire, et IO_Service :: Post () lui-même dans la piscine à la fin, quelque chose de ce genre:

#include <iostream>
#include <boost/asio.hpp>
#include <boost/thread.hpp>
boost::asio::io_service io;
boost::mutex mx;
boost::condition_variable cv;
void handler()
{
    boost::unique_lock<boost::mutex> lk(mx);
         cv.wait(lk);
    std::cout << "handler awakened\n";
    io.post(handler);
}
void buzzer()
{
    for(;;)
    {
        boost::this_thread::sleep(boost::posix_time::seconds(1));
        boost::lock_guard<boost::mutex> lk(mx);
            cv.notify_all();
    }
}
int main()
{
    io.post(handler);
    boost::thread bt(buzzer);
    io.run();
}


5 commentaires

Mais le fil qui attend sera bloqué, n'est-il pas un moyen de ne pas bloquer un fil, mais d'enregistrer un gestionnaire d'achèvement à la place? Je suis actuellement consorant un mécanisme alternatif ici Stackoverflow.com/Questtions/6776779/...


@Hassan SYED: une variable de condition est un concept qui implique un fil bloqué. Peut-être que vous recherchez des signaux asynchronisés à la place? Boost.Asio Just Ajout de la prise en charge des gestionnaires de signaux dans 1.47.0: boost.org/doc/libs/1_47_0/doc/html/boost_asio/history.html


Pour autant que je sache, ce sont des signaux émis par le système d'exploitation. Il est montré que vous pouvez vous inscrire à ces signaux, mais c'est le système d'exploitation qui les émettra.


Votre réponse est correcte, je fonctionnais sous l'hypothèse selon laquelle io_service :: exécuté () est un appel de blocage de la callee et que ASIO s'occupe de la synchronisation en quelque sorte. Je suis content que cette hypothèse n'était pas vraie.


Le lien io_service :: post dans la réponse est cassé. Était io_service :: post supprimé? Il n'apparaît pas dans la section de référence actuelle de l'ASIO DOC.



0
votes

Je peux suggérer une solution basée sur Boost :: Asio :: Date LineL_Timer qui fonctionne bien pour moi. C'est un peu d'événement asynchronisé à Boost :: Asio Environment. Une chose très importante est que le «gestionnaire» doit être sérialisé via le même «Strand_» comme «Annuler», car utiliser «Boost :: Asio :: DateLline_Timer» de plusieurs threads n'est pas un fil de sécurité.

class async_event
{
public:
    async_event(
        boost::asio::io_service& io_service,
        boost::asio::strand<boost::asio::io_context::executor_type>& strand)
            : strand_(strand)
            , deadline_timer_(io_service, boost::posix_time::ptime(boost::posix_time::pos_infin))
    {}

    // 'handler' must be serialised through the same 'strand_' as 'cancel' or 'cancel_one'
    //  because using 'boost::asio::deadline_timer' from multiple threads is not thread safe
    template<class WaitHandler>
    void async_wait(WaitHandler&& handler) {
        deadline_timer_.async_wait(handler);
    }
    void async_notify_one() {
        boost::asio::post(strand_, boost::bind(&async_event::async_notify_one_serialized, this));
    }
    void async_notify_all() {
        boost::asio::post(strand_, boost::bind(&async_event::async_notify_all_serialized, this));
    }
private:
    void async_notify_one_serialized() {
        deadline_timer_.cancel_one();
    }
    void async_notify_all_serialized() {
        deadline_timer_.cancel();
    }
    boost::asio::strand<boost::asio::io_context::executor_type>& strand_;
    boost::asio::deadline_timer deadline_timer_;
};


0 commentaires

0
votes

Malheureusement, Boost Asio n'a pas de async_wait_for_condvar () code> méthode.

Dans la plupart des cas, vous n'en aurez pas non plus besoin. La programmation de la voie ASIO signifie généralement que vous utilisez des brins, non des mautexes ou des variables de condition, pour protéger les ressources partagées. Sauf pour des cas rares, qui se concentrent généralement sur une commande de construction ou de destruction correcte au démarrage et de sortie, vous n'aurez pas besoin de mautexes ou de variables de condition du tout. P>

Lors de la modification d'une ressource partagée, le filetage classique, partiellement synchrone La façon est la suivante: p>

  • verrouiller le mutex protégeant la ressource li>
  • Mettre à jour tout ce qui doit être mis à jour LI>
  • signaler une variable de condition, si un traitement supplémentaire par un thread d'attente est requis li>
  • Déverrouillez le mutex li> ul>

    La voie d'ASIO entièrement asynchrone est cependant: p>

    • génère un message, qui contient tout, nécessaire pour mettre à jour la ressource li>
    • Postez un appel à un gestionnaire de mise à jour avec ce message à la brine de la ressource li>
    • Si un traitement supplémentaire est nécessaire, laissez ce gestionnaire de mise à jour créer un message supplémentaire (s) et les poster sur les brins de ressources apres. Li>
    • Si des emplois peuvent être exécutés sur des données entièrement privées, puis postez-les directement au contexte IO. LI> ul>

      Voici un exemple de classe quelque_shared_resource code>, qui reçoit une chaîne état code> et déclenche un autre traitement supplémentaire en fonction de l'état reçu. Veuillez noter que tous les traitements de la méthode privée quelque_shared_resource :: Receive_State () code> est entièrement sécurisé, car le brin sérialisement tous les appels. P>

      Bien sûr, l'exemple n'est pas Achevée; Quelqu'un_other_Resource Code> a besoin d'un similiaire send_code_red () code> méthode comme one_shared_ressource :: send_state () code>. p>

      #include <boost/asio>
      #include <memory>
      
      using asio_context = boost::asio::io_context;
      using asio_executor_type = asio_context::executor_type;
      using asio_strand = boost::asio::strand<asio_executor_type>;
      
      class some_other_resource;
      class some_shared_resource : public std::enable_shared_from_this<some_shared_resource> {
          asio_strand strand;
          std::shared_ptr<some_other_resource> other;
          std::string state;
      
          void receive_state(std::string&& new_state) {
              std::string oldstate = std::exchange(state, new_state);
              if(state == "red" && oldstate != "red") {
                  // state transition to "red":
                  other.send_code_red(true);
              } else if(state != "red" && oldstate == "red") {
                  // state transition from "red":
                  other.send_code_red(false);
              }
          }
      
      public:
          some_shared_resource(asio_context& ctx, const std::shared_ptr<some_other_resource>& other)
            : strand(ctx.get_executor()), other(other) {}
      
          void send_state(std::string&& new_state) {
              boost::asio::post(strand, [me = weak_from_this(), new_state = std::move(new_state)]() mutable {
                  if(auto self = me.lock(); self) {
                      self->receive_state(std::move(new_state));
                  }
              });
          }
      };
      


0 commentaires