12
votes

Comment augmentez-vous un signal dans un thread et avoir la fente correspondante exécutée dans un autre fil?

En Qt, par exemple, si vous émettez un signal dans un fil d'autrui à d'autres que le fil de l'interface graphique, le signal est en cours et exécuté plus tard dans le fil de l'interface graphique, existe-t-il un moyen de le faire avec Boost?

merci


0 commentaires

5 Réponses :


3
votes

Pas directement, car Boost ne fournit pas de boucle d'événement.

Pour avoir un signal manipulé dans un autre fil, qu'un autre fil doit vérifier la file d'attente des gestionnaires, elle doit exécuter et les exécuter (qui signifie généralement une sorte de boucle d'événement). Boost n'en fournit pas une, vous aurez donc besoin de l'obtenir d'ailleurs ou d'écrire.

Si vous avez une boucle d'événement, cela ne fournit pas de signaux, (ou implémente une solution simple avec les files d'attente), vous devriez être capable de (ab) utiliser boost.signals2 (pas boost.signals, car cette version n'est pas du thread -Safe) en remplaçant l'opérateur + = pour envelopper chaque gestionnaire dans quelque chose, cela la fitera pour l'exécution dans l'autre thread. Vous pourriez même être en mesure de le mettre en œuvre pour les signaux avec des valeurs de retour (qui n'est pas pris en charge par QT, mais est pris en charge par Boost), mais vous devrez faire attention à éviter les blocages morts.


0 commentaires

19
votes

Pour une boucle d'événement Utilisez Boost :: Asio :: io_service. Vous pouvez publier des tâches à l'intérieur de cet objet et avoir un autre fil d'exécution, dans un fil de sécurité de fil:

struct MyClass
{
    boost::io_service service;
    void doSomethingOp() const { ... }

    void doSomething()
    {
        service.post(boost::bind(&MyClass::doSomethingOp, this));
    }

    void loop()
    {
            service.run(); // processes the tasks
    }
};

boost::signal<void()> mySignal;

MyClass myClass;
mySignal.connect(boost::bind(&MyClass::doSomething, boost::ref(myClass)));

// launches a thread and executes myClass.loop() there
boost::thread t(boost::bind(&MyClass::loop(), boost::ref(myClass)));

// calls myClass.doSomething() in this thread, but loop() executes it in the other
mySignal(); 


1 commentaires

Thx pour cet échantillon très utile! Depuis Boost :: Signal est obsolète, je dois utiliser Boost :: Signals2 :: Signal <>.



1
votes

La réponse de Chila est correcte, mais il manque une chose importante: Un objet boost :: thread n'appellera que la fonction adoptée une fois. Depuis le boost :: io_service n'a pas de travail à faire avant que le signal soit émis, le fil finira immédiatement. Pour contrer cela, il y a un boost :: asio :: io_service :: travail classe. Avant d'appeler la méthode exécution () de io_service Vous devez créer un objet de travail et transmettre le io_service : xxx

Remarque: Au moment de la rédaction (Boost 1.67), cette méthode est déjà obsolète et vous êtes censé utiliser io_context :: exécuteur_work_guard (essentiellement la même fonctionnalité que io_service :: Travail ). Je n'ai pas pu compiler lorsque vous utilisez la nouvelle méthode et la solution de travail fonctionne toujours dans Boost 1.67.


0 commentaires

0
votes

Pour une raison quelconque, l'opérateur d'affectation de Boost :: Asio :: Executor_work_guard code> est supprimé, mais vous pouvez toujours le construire.

Voici ma version du code qui publie un événement code> Mouvable CODE> et le traite sur le thread exécutant io_context :: exécuté () code>: p>

class MyClass {
public:
  MyClass () : m_work(boost::asio::make_work_guard(m_service)) {}

  size_t loop() {
    return m_service.run();
  }

  void stop() {
    m_work.reset();
  }

  void doSomething(Event&& e) {
    m_service.post([this, e=std::move(e)]{ doSomethingOp(std::move(e)); });
  }

private:
  void doSomethingOp(const Event& event) {
    ...
  }
//data:
  boost::asio::io_context m_service;
  boost::asio::executor_work_guard<boost::asio::io_context::executor_type> m_work;
};


0 commentaires

3
votes

Voici un exemple complet de io_service , exécuteur_work_guard , signals2 :: signal .

    .
  • io_service est le gestionnaire de boucle d'événement
  • exécuteur_work_guard Assurez-vous que le m_service.run () n'exécute pas seulement une fois
  • signal / Slot découle l'expéditeur et le récepteur
  • the thread exécute tout le processus du io_service xxx

0 commentaires