0
votes

Attendre le fil principal jusqu'à condition

J'apprends C ++.

J'ai besoin d'attendre de recevoir des données pour démarrer le fil principal. P>

Ceci est la fonction de rappel où je vais recevoir les données dont j'ai besoin : P>

int main(int argc, char **argv)
{
  ros::init(argc, argv, "astar_controller");

  /**
   * NodeHandle is the main access point to communications with the ROS system.
   * The first NodeHandle constructed will fully initialize this node, and the last
   * NodeHandle destructed will close down the node.
   */
  ros::NodeHandle n;

  /**
   * Topic where we are going to publish speed commands.
   */
  ros::Publisher cmd_vel_pub = n.advertise<geometry_msgs::Twist>(cmdTopic, 1000);

  /**
   * Topic where we are going to receive odometry messages.
   */
  ros::Subscriber odom_sub = n.subscribe(odomTopic, 1000, odomCallback);

  ros::Rate loop_rate(10);
  //*********************************************
  // I want to wait here.
  //*********************************************

  // More code...
}


3 commentaires

STD :: Condition_Variable ?


std :: futur


@ Algirdaspreidžius merci mais je ne comprends pas l'exemple sur ce site. Je veux relâcher la serrure sur le dernier si condition: si (is_init_pos) .


3 Réponses :


2
votes

globalement, déclarez une variable de condition et un mutex qui sont partagés entre le fil de rappel et le principal. Et un booléen qui est sous la serrure mutex.

  //*********************************************
  // I want to wait here.
  //*********************************************

   // Wait for odomCallback to signal its done

    {
       std::unique_lock<std::mutex> lock(g_mutex);
       while (g_isReady == false)
       {
           g_cv.wait(lock);
       }
    }


3 commentaires

Même si la solution est correcte, votre dernière boucle ( tandis que (g_isready == false) ) peut être simplifié à g_cv.wait (verrouiller, [] {retour g_isready;});


La dernière partie, après // attendre que OdomCallback signalait son bloque tout: je ne reçois aucun message dans OdomCallback et je ne peux pas tuer le programme avec CTRL. + C. Peut-être parce qu'il bloque le fil principal (je suppose, je n'ai aucune idée de la filetage en C ++).


@Vansfannel - Êtes-vous sûr que OdomCallback est-il invoqué? Sinon, êtes-vous absolument certain que odomcallback devrait être appelé sur un thread différent - ou si ce cadre s'attend-il à ce que vous penchiez des messages sur le thread principal (par conséquent, ce n'est pas vraiment un problème de threading).



0
votes

edit: Je ne pense pas que vous soyez censé utiliser plusieurs threads. Vous attendez des rappels en exécutant un "" boucle d'événement " dans le fil principal . xxx

voir http: / /wiki.ros.org/rospp/overview/callbacks%20and%20Spinning


La réponse originale suit:

Tout d'abord, Le is_init_pos variable doit être sûr d'accéder simultanément à partir de plusieurs threads. Sinon, si le fil principal le lit alors que le fil de rappel l'écrit, votre programme aura un comportement indéfini. Ainsi, utilisez un mutex pour synchroniser l'accès au booléen et utiliser une variable de condition pour envoyer une notification lorsque son état change: xxx

la fonction de rappel doit verrouiller ce mutex lors de l'accès à < Code> is_init_pos et envoyez une notification sur la variable de condition: xxx

Maintenant, le thread principal peut attendre sur la variable de condition pour recevoir une notification lorsque l'état change: xxx

Le thread bloquera sur le condition_variable :: wait appelez et ne reviendra que après qu'il soit réveillé par une notification et qu'il voit une valeur réelle pour la condition associée (définie comme une expression Lambda teste la variable booléenne). Bien qu'il n'y ait aucune notification ou que la condition est fausse, elle continuera à attendre.


EDIT: P.S. La réponse similaire de Selbie pourrait être très légèrement plus efficace, car seule la variable g_isready est partagée entre les deux threads. Il n'est donc pas nécessaire de verrouiller le mutex dans le rappel à chaque fois, uniquement sur le premier appel: < / p> xxx

et dans le fichier fileter utilise [] {return g_isready; }; pour la condition.

Ceci utilise une variable BOOL supplémentaire, mais évite de verrouiller le mutex sur chaque rappel. Cela ne fera probablement pas beaucoup de différence dans la pratique, donc dans ma réponse, je viens de réutiliser la variable is_init_pos que vous avez déjà.


7 commentaires

La dernière partie, après // nouvelle portée imbriquée qui détermine la durée du verrouillage mutex , bloque tout: je ne reçois aucun message dans odomcallback et je ne peux pas Tuez le programme avec CTRL. + c. Peut-être parce qu'il bloque le fil principal (je suppose, je n'ai aucune idée de la filetage en C ++).


Ensuite, vous avez fait quelque chose de mal. Peut-être que vous avez oublié de changer le rappel pour l'informer de la variable de condition. Peut-être que vous avez oublié d'ajouter le init_cv.wait (verrouillage, condition); ligne.


Non, j'ai tout copié de votre réponse. J'ai vérifié double vérité.


Ensuite, cela signifie que le rappel n'arrive pas. Êtes-vous sûr que les rappels se produisent sur un fil séparé? Peut-être que vous êtes censé créer une boucle pair dans principale qui attendra les rappels dans le fil principal . Je viens de regarder wiki.ros.org et je ne pense pas que cela fonctionne comme vous pensez que cela fonctionne. Tu n'es pas censé appeler ros :: spin () pour attendre les rappels? Pourquoi essayez-vous d'utiliser plusieurs threads? Avez-vous essayé l'exemple à wiki.ros.org/ros/ Tutoriels / ... ?


Oui, j'utilise cet exemple. J'apprends et j'essaie maintenant de comprendre comment les rappels de Ros fonctionnent. Laissez-moi voir ce que ça se passe et je vais vous dire. Merci beaucoup pour votre temps et votre aide.


Lisez wiki.ros.org/roscpp/overview/Callbacks%20and%20Spinning - Si vous voulez que les rappels se produisent sur un autre fil, vous devez créer un autre fil . Cela ne se produira pas par magie.


La magie est quelque chose d'intéressant.