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

Threads & Processus C++ Discussion :

[MT] Galère avec thread et mutex pour accès variable


Sujet :

Threads & Processus C++

  1. #1
    Membre averti
    Inscrit en
    Mai 2005
    Messages
    44
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 44
    Par défaut [MT] Galère avec thread et mutex pour accès variable
    Salut, comme l'indique mon titre, je suis en train de faire mon entrée dans le monde des threads et je galère un peu.

    j'ai une classe TOTO de la forme : (je mélange déclaration et définition pour limité la longueur du post)
    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
    class TOTO
    {
        public : 
        void recup_mesg()  // récupération des message
        {
           pthread_mutex_lock( &verrou ); 
           ret.nb=recv(info.id,ret.buf,1500,0); // info.id est une socket tcp
                                                    //surlaquelle je recois des message en xml
           pthread_mutex_unlock( &verrou );
        }
        Recv get_mesg() // retourne ma variable
        {
           Recv temp;
           pthread_mutex_lock( &verrou );
           temp = ret;
           pthread_mutex_unlock( &verrou );
           return temp;
        }
     
        private : 
        Recv ret;
        pthread_mutex_t verrou;
    }
     
     
    //AVEC : 
    typedef struct
    {
        int nb;             // Nombre d'octets recus
        char buf[1500];
    } Recv;
    le principe c'est que j'ai un thread qui fais une boucle pour récupérer mes messages (et elle les place temporairement dans ma varaible ret) avec recup_mesg
    et un autre thread qui est censé récupéré les message l'un après l'autre avec la fonction get_mesg pour les parser.

    le problème c'est que si je fais un cout de ret.buf au niveau de la fonction recup_mesg, j'obtiens bien mon text xml brut, mais si je le fais dans la fonction get_mesg, j'obtiens un truc bizarre (en l'occurrence un m$ )

    je vois pas vraiment d'où ça vient, je me demande si ça ne serait pas un problème de verouillage, mais je ne pense pas.

    merci de votre aide !

  2. #2
    Membre Expert
    Avatar de coyotte507
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    1 327
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 327
    Par défaut
    Salut,

    Je ne pense pas que ce soit un problème de verrouillage non plus, est-ce qu'on peut voir ton code cpp (tu peux le simplifier pour juste laisser le problème)?

    coyotte507

  3. #3
    Membre averti
    Inscrit en
    Mai 2005
    Messages
    44
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 44
    Par défaut
    alors voilà ce que ça donne quand on "regroupe" mes différents fichiers :

    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
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    --- definition des methodes et classes ---
     
    class Listener
    {
        public:
     
        Listener();
        void lecture(); // lecture sur la socket
        Recv get_buffer(); // renvoie du buffer
        void set_listener(Sock L_socket); //mis en place de la socket
     
        pthread_mutex_t verrou;
     
        private:
     
        Sock listener; // structure contenant la socket
        Recv ret;
     
    };
     
     
    void Listener::lecture()
    {
        cout << "Lancement de la lecture" << endl;
        while (1)
        {
            ret.nb = -1; // on reset la variable
            memset (ret.buf, 0, sizeof (ret.buf)); // on reset la variable
            pthread_mutex_lock( &verrou );
            ret=recv(listener);
            pthread_mutex_unlock( &verrou );
            cout << "sortie 1" << ret.buf << endl;
        }
    };
     
     
    Recv Listener::get_buffer()
    {
        Recv temp;
        cout << "sortie 2" << ret.buf << endl;
        pthread_mutex_lock( &verrou );
        temp = ret; // on stop dans un temps sinon on peut pas dévérouiller si on fait le return
        pthread_mutex_unlock( &verrou );
        return temp;
    };
     
     
     
    class Parseur
    {
        public:
     
        Parseur();
        void make_parse(); // fct qui fait le parse !
        void action();
     
        private:
     
        Listener listen;
        Recv buffer;
     
    };
     
     
    void Parseur::action()
    {
        while (1)
        {
            buffer.nb = -1;
            memset (buffer.buf, 0, sizeof (buffer.buf));
            buffer = listen.get_buffer(); // on récup le Recv de l'objet listener (en gros la variable ret)
            cout << "sortie 3" << buffer.buf << endl;
            make_parse();
        }
    };
     
     
     
    ------Main------ 
     
    // initialisation des deux objets
    Listener ecouteur;
    Parseur decoupeur;
     
    lance un thread qui excute la methode Listener::lecture
    x_Filament_Ameliore<Listener> fil_ecouteur(&ecouteur, &Listener::lecture);
     
    lance un thread qui excute la methode Parseur::action
    x_Filament_Ameliore<Parseur> fil_decoupeur(&decoupeur, &Parseur::action);
     
    // et là ça merde ! :D
    sur la sortie 1 j'obtiens bien mes messages xml brut les un après les autres
    sur les sorties 2 et 3 j'ai un : m$ qui apparait.

    voilà je crois que j'ai tout dit
    merci du coup de main !

  4. #4
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Par défaut
    Tes deux threads peuvent écrire au même emplacement mémoire au même moment.
    Ça s'appelle un race condition, et c'est un comportement indéfini.

    De plus, tu lis la donnée pendant qu'un autre thread peut être en train d'écrire dessus, donc c'est pas étonnant si le résultat n'est pas bon.

  5. #5
    Membre averti
    Inscrit en
    Mai 2005
    Messages
    44
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 44
    Par défaut
    De plus, tu lis la donnée pendant qu'un autre thread peut être en train d'écrire dessus, donc c'est pas étonnant si le résultat n'est pas bon.
    mais le but d'utiliser des verrous c'est pas de palier à ce problème ?

  6. #6
    Membre averti
    Inscrit en
    Décembre 2006
    Messages
    31
    Détails du profil
    Informations forums :
    Inscription : Décembre 2006
    Messages : 31
    Par défaut mutex
    Salut,

    Essaye de rajouter un autre mutex qui gere l'impression.

    Je me demande egalement si ce ne searait pas pertinent d'avoir des mutex separes pour la reception et la transmission

  7. #7
    Membre averti
    Inscrit en
    Mai 2005
    Messages
    44
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 44
    Par défaut
    Salut alpidor,

    je vois pas trop où tu veux en venir, le seul cout où j'aurais éventuellement besoin de mettre un mutex c'est celui de la sortie 2, mais même avec ça change rien

    pour ce qui est des mutex séparés, je te suis pas trop. Tu penses qu'ils faudrait que j'utilises des verrous différents dans mes deux méthodes ? je vois pas l'intérêt parce que si c'est pas le même verrous, il ne va pas y avoir blocage entre les deux méthodes, si ?

  8. #8
    Membre averti
    Inscrit en
    Décembre 2006
    Messages
    31
    Détails du profil
    Informations forums :
    Inscription : Décembre 2006
    Messages : 31
    Par défaut mutex
    Salut,

    D'habitude, la communication est full-duplex et je pense qu'elle doit le rester.
    Si tu mets le meme mutex pour les deux cette propriete precieuse disparaitra a mon sens.

    Pour l'impression : essaye de mettre un mutex et voir quel effet aura.

    A+

  9. #9
    Membre averti
    Inscrit en
    Mai 2005
    Messages
    44
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 44
    Par défaut
    mais ça va quand même bloqué si les mutex sont différents ?

  10. #10
    Membre averti
    Inscrit en
    Mai 2005
    Messages
    44
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 44
    Par défaut
    alors, j'ai renommé le verrou dans get_buffer, en verrou2 et j'ai rajouté un verrou3 sur la sortie 2.

    j'ai enlevé les sorties 1 et 3 qui ne me servent à rien pour le moment.

    et résultat la sortie 2 me donne : @à
    alors qu'avant j'avais un m$
    est-ce encourangeant !

  11. #11
    Membre averti
    Inscrit en
    Décembre 2006
    Messages
    31
    Détails du profil
    Informations forums :
    Inscription : Décembre 2006
    Messages : 31
    Par défaut mutex
    pour quelle raison mets-tu des mutex sur les entrees et les sorties?
    il faudrait que je vois ton design

  12. #12
    Membre Expert
    Avatar de coyotte507
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    1 327
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 327
    Par défaut
    Voila des améliorations que je ferais:

    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
    void Listener::lecture()
    {
        cout << "Lancement de la lecture" << endl;
        while (1)
        {
            ret.nb = -1; // on reset la variable
            memset (ret.buf, 0, sizeof (ret.buf)); // on reset la variable
            pthread_mutex_lock( &verrou );
            ret=recv(listener);
            cout << "sortie 1: " << ret.buf;
            pthread_mutex_unlock( &verrou );
        }
    };
     
     
    Recv Listener::get_buffer()
    {
        Recv temp;
        pthread_mutex_lock( &verrou );
        cout << "sortie 2" << ret.buf << endl;
        temp = ret; // on stop dans un temps sinon on peut pas dévérouiller si on fait le return
        pthread_mutex_unlock( &verrou );
        return temp;
    };
    J'ai juste mis les cout entre les verrous et pas en dehors, aussi il y avait un 'buffer.buf' dans lecture(), je vois buffer nulle part dans la classe Listener, j'ai remplacé par "ret.buf".

    Tu as toujours ton problème?

  13. #13
    Membre averti
    Inscrit en
    Mai 2005
    Messages
    44
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 44
    Par défaut
    Malheureusement pas de changement

    pour le buffer.buf, c'est une erreur de recopiage c'était bien un ret.buf qu'il fallait.



    Citation Envoyé par alpidor
    pour quelle raison mets-tu des mutex sur les entrees et les sorties?
    il faudrait que je vois ton design
    disons que je ne sais pas trop, je ne connais pas vraiment (du tout) le fonctionnement des mutex, donc je me base sur ce que les gars qui sont en stage avec moi me disent !
    qu'entends tu pars "design" ?

  14. #14
    Membre Expert
    Avatar de coyotte507
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    1 327
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 327
    Par défaut
    bon juste pour voir s'il c'est un problème d'interférence, essaie ça:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    void Listener::lecture()
    {
        cout << "Lancement de la lecture" << endl;
        while (1)
        {
            ret.nb = -1; // on reset la variable
            memset (ret.buf, 0, sizeof (ret.buf)); // on reset la variable
            pthread_mutex_lock( &verrou );
            ret=recv(listener);
            cout << "sortie 1: " << ret.buf;
            pthread_mutex_unlock( &verrou );
            get_buffer();
        }
    };
    Sinon j'ai remarqué quelquechose: while(1). En fait, en gros, tu fais une boucle infinie, t'attends de recevoir quelquechose, et tu repars pour une boucle. Dans ces condition ton verrou est quasiment toujours là, c'est peut être ca le problème.
    Ta fonction recv() est bloquante :s. Normalement, si ma théorie est juste, dans le code de la fonction lecture() ci-dessus, la fonction get_buffer() marchera (je parle lorsqu'elle est appelée dans cette fonction comme ci-dessus).

    Si c'est le cas (je me trompe peut être), alors il faudra trouver une méthode non bloquante pour ne pas monopoliser le verrou, et faire un sleep(10) à la fin de ta boucle infinie pour ne pas monopoliser le verrou.

  15. #15
    Membre averti
    Inscrit en
    Mai 2005
    Messages
    44
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 44
    Par défaut
    t'as pas faux ça marche bien.

    le problème c'est que je ne peux pas faire un sleep parce que mon entité de l'autre côté de ma socket envoie des message en continue, donc si je perds attends un moment je vais avoir le buffer tcp qui va se remplir, et à ce moment là je vais me retrouver dans mon receive avec la fin d'un message et le début d'un autre.

    à la rigueur je peux essayer de jouer sur quelques centièmes de secondes avec le Sleep sous windows, mais sous linux, je peux pas le faire, sleep fonctionne en seconde avec des int !

  16. #16
    Membre Expert
    Avatar de coyotte507
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    1 327
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 327
    Par défaut
    Dans ce cas faut chercher une méthode non bloquante pour pas bloquer le verrou. Et si tu veux tu peux aussi chercher une méthode pour faire une attente d'un centième de seconde.

    Sinon en testant (juste pour voir), est-ce que en mettant le sleep() (même si c'est en secondes), tu as ton problème?

    Edit: accept est bloquante

  17. #17
    Membre Expert
    Avatar de coyotte507
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    1 327
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 327
    Par défaut
    Sinon, idée?

    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
    44
    45
    class Listener
    {
        public:
     
        Listener();
        void lecture(); // lecture sur la socket
        Recv get_buffer(); // renvoie du buffer
        void set_listener(Sock L_socket); //mis en place de la socket
     
        pthread_mutex_t verrou;
     
        private:
     
        Sock listener; // structure contenant la socket
        Recv ret;
     
    };
     
     
    void Listener::lecture()
    {
        cout << "Lancement de la lecture" << endl;
        while (1)
        {
            Recv temp;//temp, on n'utilise pas celui dans la classe pour pas bloquer le verrour
            temp.nb = -1; // on reset la variable
            memset (temp.buf, 0, sizeof (temp.buf)); // on reset la variable
            temp=recv(listener);
            pthread_mutex_lock( &verrou );
            ret = temp; //copiage
            pthread_mutex_unlock( &verrou );
            cout << "sortie 1" << temp.buf << endl;
        }
    };
     
     
    Recv Listener::get_buffer()
    {
        Recv temp;
        pthread_mutex_lock( &verrou );
        cout << "sortie 2" << ret.buf << endl;
        temp = ret; // on stop dans un temps sinon on peut pas dévérouiller si on fait le return
        pthread_mutex_unlock( &verrou );
        return temp;
    };
    J'ai utilisé une variable temp dans lecture() pour recevoir (comme ca on n'a pas besoin de verrour pour la fonction recv qui est bloquante).
    Après on copie temp dans ret. (et le verrou est seulement là).

    Ca marche?

  18. #18
    Membre averti
    Inscrit en
    Mai 2005
    Messages
    44
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 44
    Par défaut
    et puis avec accept ça me permettra pas de recevoir mon message

    sinon, j'ai essayé le Sleep sous windows avec différentes tempo jusqu'à 1 seconde et ça marche pas :d

    si receive est bloquante, le seule truc que j'ai à faire c'est de m'arranger pour que mon get_buffer dans mon autre thread ne s'éxécute pas tant que c'est bloqué. le problème comment :d

    EDIT : ma réponse correspond à ton premier post de la page :d

  19. #19
    Membre averti
    Inscrit en
    Mai 2005
    Messages
    44
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 44
    Par défaut
    et ben toujours pas ça !
    c'est drole c'est ce que j'allais tester juste avant d evoir ta réponse :d

    je suis revenu au m$ sur la sortie !

  20. #20
    Membre Expert
    Avatar de coyotte507
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    1 327
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 327
    Par défaut
    je sais pas si lors du copiage de char[], c'est pas juste l'adresse du tableau qui est copié (lequel serait désalloué à chaque boucle).

    Peut être il faut faire un strcpy?

    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
     
    //#include <cstring>
    void Listener::lecture()
    {
        cout << "Lancement de la lecture" << endl;
        while (1)
        {
            Recv temp;//temp, on n'utilise pas celui dans la classe pour pas bloquer le verrour
            temp.nb = -1; // on reset la variable
            memset (temp.buf, 0, sizeof (temp.buf)); // on reset la variable
            temp=recv(listener);
            pthread_mutex_lock( &verrou );
            ret.nb = temp.nb; //copiage
            strcpy (ret.buf, temp.buf); //copiage
            pthread_mutex_unlock( &verrou );
            cout << "sortie 1" << temp.buf << endl;
        }
    };

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Apache en mode Proxy avec Tomcat 7 pour accès HTTPS
    Par Papimougeot dans le forum Apache
    Réponses: 3
    Dernier message: 08/08/2013, 09h31
  2. Réponses: 1
    Dernier message: 06/05/2013, 17h47
  3. Problème avec Thread et invoke pour maj une textbox
    Par drichnifu dans le forum VB.NET
    Réponses: 3
    Dernier message: 30/03/2012, 17h36
  4. problème avec mon code pour accès au serveur ftp
    Par mimi51340 dans le forum Général Java
    Réponses: 1
    Dernier message: 03/03/2008, 23h24
  5. galère avec my2pg.pl
    Par fafet dans le forum PostgreSQL
    Réponses: 4
    Dernier message: 16/07/2003, 10h10

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