IdentifiantMot de passe
Loading...
Mot de passe oubli� ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les r�ponses en temps r�el, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

[C++] Synchroniser deux threads


Sujet :

C++

Vue hybride

Message pr�c�dent Message pr�c�dent   Message suivant Message suivant
  1. #1
    Membre Expert
    Avatar de Aspic
    Homme Profil pro
    �tudiant
    Inscrit en
    Ao�t 2005
    Messages
    3 905
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (�le de France)

    Informations professionnelles :
    Activit� : �tudiant
    Secteur : High Tech - �lectronique et micro-�lectronique

    Informations forums :
    Inscription : Ao�t 2005
    Messages : 3 905
    Par d�faut [C++] Synchroniser deux threads
    Bonsoir,

    J'utilise la librairie pthread pour cr�er mes threads et je suis face � un probl�me de synchronisation :
    Je travaille sur la recherche bidirectionnelle dans un graphe.

    J'ai donc cr�er une fonction qui fait une recherche de l'�tat initial vers l'�tat final (forward) et une autre qui fait dans l'autre sens (backward)

    Les �tapes de l'algorithme sont les suivants :
    1. Tant que la solution n'est pas trouv�e :
    2. R�cup�rer le r�sultat de la recherche FORWARD
    3. R�cup�rer le r�sultat de la recherche BACKWARD
    4. Faire un test d'union entre les deux recherches
    5. Si ce test est concluant alors quitter l'algo sinon continuer


    En s�quentiel, ca marche tr�s bien mais je n'arrive pas � parall�liser la recherche BACKWARD (la recherche FORWARD sera faite dans le thread principal).

    L'id�e serait :
    • Cr�er le thread de recherche pour BACKWARD (qui sera en boucle infinie)
    • Tant que la solution n'est pas trouv�e : (thread principal)
    • R�cup�rer le r�sultat de la recherche FORWARD (thread principal)
    • Attendre que le thread ait fini le premier tour
    • Faire un test d'union entre les deux recherches (thread principal)
    • Si ce test est concluant alors quitter l'algo sinon continuer (thread principal)


    Je dois utiliser les threads avec conditions (et peut �tre des mutex) mais voil�, je s�che.

    A mon avis, c'est pas clair car ce n'est pas clar pour moi non plus

    Avez vous une id�e ?

    Merci d'avance
    Qui ne tente rien n'a rien !
    Ce qui ne nous tue pas nous rends plus fort !!
    Mon projet ZELDA en C++/Allegro
    http://www.tutoworld.com - Le Forum -
    Mes ressources Dotnet (cours, sources, tutos)
    --------------------------------------------
    + + =

    Ne pas oublier le Tag !

  2. #2
    Invit�
    Invit�(e)
    Par d�faut
    Salut
    A priori une recherche ne modifie pas les donn�es que l'on parcourt donc tu ne devrais pas avoir besoin de mutex :
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    void rechercheBackward(const Graphe & graphe, Resultat & resultat) { ... }
    void rechercheForward(const Graphe & graphe, Resultat & resultat) { ... }
    ...
    // recherches backward et forward en parallele
    std::thread threadBackward ( rechercheBackward, std::cref(monGraphe), std::ref(resultatBackward) );
    rechercheForward(monGraphe, resultatForward);
    threadBackward.join();
    // union des 2 recherches
    ...
    http://en.cppreference.com/w/cpp/thread/thread/thread
    Si tu veux absolument utiliser la lib pthread, le code devrait �tre assez similaire.

  3. #3
    Membre Expert Avatar de Ehonn
    Homme Profil pro
    �tudiant
    Inscrit en
    F�vrier 2012
    Messages
    788
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 35
    Localisation : France

    Informations professionnelles :
    Activit� : �tudiant
    Secteur : High Tech - �diteur de logiciels

    Informations forums :
    Inscription : F�vrier 2012
    Messages : 788
    Par d�faut
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    std::thread threadBackward ( rechercheBackward, std::cref(monGraphe), std::ref(resultatBackward) );
    Avec std::thread, j'aime bien passer par une lambda du genre :
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    std::thread threadBackward([&]() { rechercheBackward(monGraphe, resultatBackward); });
    Et dans notre cas, une fonction qui retourne quelque chose est l�gitime (resultatBackward).
    Donc avec une fonction de ce genre : return_t backward(graph_t const &), on peut utiliser une std::future :
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    auto f = std::async(std::launch::deferred, [&]() -> return_t { return resultatBackward(monGraphe); });
    // ...
    auto resultatBackward = f.get() // Pour récupérer le résultat (faire un seul appel à .get() car le résultat peut être déplacé)
    Edit : nokomprendo > oui, il manque bien le return (erreur copier / coller)

  4. #4
    Invit�
    Invit�(e)
    Par d�faut
    Oui tu as raison mais comme il �tait parti sur du pthread, je n'ai pas voulu trop le brusquer...

    Pour la lambda, personnellement je pr�f�re expliciter la fermeture (surtout s'il y a des r�f�rences) et �viter le type de retour s'il peut �tre d�duit; et je crois qu'il manque un return :
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    auto f = std::async(std::launch::deferred, [&monGraphe]() { return resultatBackward(monGraphe); });
    // ...
    Par contre, je ne suis pas fan de la lambda ici car il y doit y avoir un (l�ger) surco�t pour la cr�er et de plus on ne peut pas sp�cifier la r�f�rence captur�e en const (ou du moins, je ne sais pas comment faire). Donc, je pr�f�re vraiment :
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
     
    auto f = std::async(std::launch::deferred, resultatBackward, std::cref(monGraphe) );
    // ...

  5. #5
    Membre Expert Avatar de Ehonn
    Homme Profil pro
    �tudiant
    Inscrit en
    F�vrier 2012
    Messages
    788
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 35
    Localisation : France

    Informations professionnelles :
    Activit� : �tudiant
    Secteur : High Tech - �diteur de logiciels

    Informations forums :
    Inscription : F�vrier 2012
    Messages : 788
    Par d�faut
    Citation Envoy� par nokomprendo Voir le message
    Pour la lambda [...] et je crois qu'il manque un return :
    Merci, c'est corrig�.

    Citation Envoy� par nokomprendo Voir le message
    Pour la lambda, personnellement je pr�f�re expliciter la fermeture
    Dans le cas g�n�ral je n'ai pas trop d'avis l� dessus. Mais ici on se sert de la lambda comme on aurait pu utiliser std::bind ou un simple foncteur. Plus le code de la lambda sera court plus il sera facile de voir que l'on cherche � transformer un appel de fonction � N arguments en un appel de fonction sans argument. Donc dans ce cas, j'ai une petite pr�f�rence � ne pas expliciter la liste de capture ainsi que le type de retour.

    Citation Envoy� par nokomprendo Voir le message
    Par contre, je ne suis pas fan de la lambda ici car il y doit y avoir un (l�ger) surco�t pour la cr�er et de plus on ne peut pas sp�cifier la r�f�rence captur�e en const (ou du moins, je ne sais pas comment faire). Donc, je pr�f�re vraiment :
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
     
    auto f = std::async(std::launch::deferred, resultatBackward, std::cref(monGraphe) );
    // ...
    S'il y a un surco�t d� � la lambda, il faut changer de compilateur. Les lambdas sont forc�ment inline et devraient �tre inlin�.
    J'aime bien la lambda car elle permet de ne pas oublier les std::ref ou std::cref et quelle s'adapte automatiquement si ces "d�tails" changent.
    Oui, on ne peut capturer que par copie ou r�f�rence. Mais rien n'emp�che d'avoir un code proche de :
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    std::async(std::launch::deferred, [&]() { return resultatBackward(fonction_qui_prend_un_T_ref_et_qui_retourne_un_T_const_ref(monGraphe)); });

  6. #6
    Invit�
    Invit�(e)
    Par d�faut
    @Ehonn: je ne suis pas expert en compilation mais il me semble qu'une lambda n'est qu'un raccourci syntaxique pour un objet-fonction donc cela implique effectivement un surc�ut dans la taille de l'ex�cutable alors que ce n'est pas le cas si on utilise un bind ou directement la fonction.
    Concernant les std::ref et std::cref, il ne faut effectivement pas les oublier mais ils permettent d'�viter des erreurs genre "modifier une donn�e qui devrait �tre const mais que la lambda a adapt� automatiquement".
    Ceci dit, tout �� c'est du d�tail, les deux solutions fonctionnent bien.

    @Aspic: si je comprends bien ton probl�me, tu veux chercher dans un graphe dans deux sens en m�me temps, tout arr�ter quand tu as trouv� et tout �� en �vitant de traiter des noeuds d�j� trait�s (overlapping) ?
    � mon avis, une solution simple est que les deux recherches s'observent mais sans acc�s "concurrent" (lecture-�criture et non �criture-�criture) :
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
     
    bool foundForward = false;
    bool foundBackward = false;
     
    void rechercheForward(...) {
    	// rechercheForward modifie les donnees forward et observe les donnees backward
    	while (not (foundForward or foundBackward or forwardStates.empty()) {
    		// mettre à jour forwardStates
    		// mettre à jour foundForward si on a trouve
    	}
    }
     
    void rechercheBackward(...) {
    	// rechercheBackward modifie les donnees backward et observe les donnees forward
    	while (not (foundBackward or foundForward or backwardStates.empty()) {
    		// mettre à jour backwardStates
    		// mettre à jour foundBackward si on a trouve
    	}
    }
     
    int main() {
    	std::thread t(rechercheBackward...);
    	rechercheForward(...);
    	t.join(); 
    	if (foundForward)
    		// récupérer le résultat de la recherche forward
    	else if (foundBackward)
    		// récupérer le résultat de la recherche backward
    	else
    		// non trouvé
    }
    Cet exemple ne traite pas l'overlapping mais avec une variable partag�e + mutex ce ne doit pas �tre difficile.
    Concernant ton probl�me de std::thread, �� m'�tonne car c'est juste une surcouche (souvent � pthread justement).
    Bref, j'esp�re que tout �� t'aidera et d�sol� si ce n'est pas la meilleure solution/impl�mentation ou si j'ai juste rien compris � ton probl�me.
    Derni�re modification par Invit� ; 08/11/2015 � 16h03.

  7. #7
    Membre Expert
    Avatar de Aspic
    Homme Profil pro
    �tudiant
    Inscrit en
    Ao�t 2005
    Messages
    3 905
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (�le de France)

    Informations professionnelles :
    Activit� : �tudiant
    Secteur : High Tech - �lectronique et micro-�lectronique

    Informations forums :
    Inscription : Ao�t 2005
    Messages : 3 905
    Par d�faut
    Citation Envoy� par nokomprendo Voir le message
    Salut
    A priori une recherche ne modifie pas les donn�es que l'on parcourt donc tu ne devrais pas avoir besoin de mutex :
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    void rechercheBackward(const Graphe & graphe, Resultat & resultat) { ... }
    void rechercheForward(const Graphe & graphe, Resultat & resultat) { ... }
    ...
    // recherches backward et forward en parallele
    std::thread threadBackward ( rechercheBackward, std::cref(monGraphe), std::ref(resultatBackward) );
    rechercheForward(monGraphe, resultatForward);
    threadBackward.join();
    // union des 2 recherches
    ...
    http://en.cppreference.com/w/cpp/thread/thread/thread
    Si tu veux absolument utiliser la lib pthread, le code devrait �tre assez similaire.
    Bonjour,

    Je n'utilise pas std::thread car mon compilateur ne la g�re pas c'est pour ca que je souhaite passer par pthread. (et puis je ne suis pas tr�s � l'aise avec les lambda )

    J'ai d�j� essay� avec pthread ton approche mais ca n'a pas march�, certainement parce que je m'y suis mal pris

    Soit ma fonction
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    void rechercheBackward(...) {  
        while (!solved_backward && !backwardStates.empty())
        {  
            // ...
        }
    }
    void rechercheForward(...) {  
        while (!solved_forward && !forwardStates.empty())
        {  
            // ...
        }
    }
    Et celui qui appelle les fonctions :
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     
    int main()
    {
          // création du thread avec pthread qui lance rechercheBackward(...) en parralèle
         Thread thread = pthread_create(...)
         while (!solved_forward && !forwardStates.empty()
                && !solved_backward && !backwardStates.empty())
         {
               rechercheForward(....);
     
               // Attente du thread rechercheBackward()
               pthread_join(&thread, NULL);
     
                // Union des recherches
         }
    }
    Le probl�me est que pthread_join() attend que le thread rechercheBackward() soit quitt� et vu qu'il est en boucle infinie... mon thread principal reste bloqu�... A mon avis, il faut utiliser pthread_cond_wait() et pthread_cond_signal() mais je n'y arrive pas.

    Voil� un "pseudo" code de la version s�quentielle qui marche tr�s bien (tous les cas en sont pas g�r�s, c'est pour simplifier le code)
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    bool AlgoBidirect::start()
    {
        bool overlapped = false;
        Node* current_fw = NULL, *current_rv=NULL;
        std::vector<Node*> succ, pred , nodes;
        std::queue<Node*> forwardStates, backwardStates;
     
        // Insert initial nodes in queue
        forwardStates.push(/* initial node */);
        backwardStates.push(/* initial node */);
     
        while (!solved_forward && !forwardStates.empty()
                && !solved_backward && !backwardStates.empty()
    			)
        {
            // Forward
            {
                // Get first node in frontier
                current_fw = forwardStates.front(); forwardStates.pop();
     
                // Get successors and check if current_fw is a goal state
                succ = this->m_forward->_checkNode(current_fw, this->m_solved_forward);
                for (const auto& n : succ)
                    forwardStates.push(n);
            }
     
            // Backward
            {
                current_rv = backwardStates.front(); backwardStates.pop();
     
                // Get successors and check if current_rv is a goal state
                pred = this->m_backward->checkNode(current_rv, this->m_solved_backward);
                for (const auto& n : pred)
                    backwardStates.push(n);
            }
     
            // Find overlapping between forward and reverse
    		{
                overlapped = checkMergeBetweenFwAndBw(...);
    		}
        }
    	// ici on a trouvé si overlapped = true
    }
    Merci
    Qui ne tente rien n'a rien !
    Ce qui ne nous tue pas nous rends plus fort !!
    Mon projet ZELDA en C++/Allegro
    http://www.tutoworld.com - Le Forum -
    Mes ressources Dotnet (cours, sources, tutos)
    --------------------------------------------
    + + =

    Ne pas oublier le Tag !

Discussions similaires

  1. R�ponses: 2
    Dernier message: 17/10/2013, 23h39
  2. R�ponses: 7
    Dernier message: 25/03/2013, 08h10
  3. R�ponses: 1
    Dernier message: 23/03/2013, 22h21
  4. R�ponses: 6
    Dernier message: 13/09/2010, 16h02
  5. synchronisation entre deux threads
    Par chabfive dans le forum Concurrence et multi-thread
    R�ponses: 9
    Dernier message: 03/11/2006, 12h17

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo