Publicité
+ Répondre à la discussion
Affichage des résultats 1 à 6 sur 6
  1. #1
    Futur Membre du Club
    Inscrit en
    novembre 2007
    Messages
    59
    Détails du profil
    Informations forums :
    Inscription : novembre 2007
    Messages : 59
    Points : 19
    Points
    19

    Par défaut Conseil utilisation de la lib GNU pthread

    Bonjour à tous!

    Je découvre la programmation multi threade, et je me suis dit que le mieux était d'essayer la lib pthread, en faisant un "producteur-consommateur" (un thread essaye d'écrire dans un tableau, un autre thread essaye de lire ce tableau).
    Vu que c'est la premiere fois que je vais ça, je voulais savoir si la logique et la méthode était bonne, si l'architecture du programme était logique, et enfin si vous auriez fait pareil ou pas (pour améliorer ma technique).
    (Une fois mon programme écrit, je me suis inspiré de http://franckh.developpez.com/tutoriels/posix/pthreads/ pour corrigé certains problèmes)

    Fonctionnement :
    Pour cela, j'ai un main, qui lance 2 threads (puis fait un sleep 2): l'un qui lit dans le tableau nommé i_tab de taille RESOURCE_SIZE, et l'autre qui écrit dans ce tableau.
    Le thread producteur, s'il est exécuté, boucle à l'infini et remplis le tableau s'il y a assez de place, et le thread consommateur libère de la place dans le tableau s'il n'est pas vide.

    L'algo que j'utilise pour le thread consommateur :
    1-Rentrer en section critique
    2-S'il y a des choses à lire dans le tableau:
    En lire iNb (dans mon cas c'est toujours 1, donc en lire 1!).
    Envoyer un signal comme quoi le tableau n'est pas rempli (car j'ai lu 1 élement!)
    Sortir de section critique.
    Recommencer en 1.

    S'il n'y a rien à lire dans le tableau:
    Se mettre en attente du thread producteur qui remplira le tableau
    Sortir de section critique.


    Mon code pour le thread consommateur :
    Je mets uniquement la fonction de lecture (consommateur) (le producteur ayant la même architecture, sauf qu'avant d'écrire, on teste s'il reste de la place dans le tableau au lieu de tester si le tableau est vide!), et je ne mets pas le main non plus, ça ne sert à rien, car je fais juste:
    1-lancer le thread lecture;
    2-lancer le thread écriture;
    3-sleep(2);

    Code :
    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
    /*! \param[in] iNb: nb data to read
    *   \param[in] psResource (struct containing mutex, table and actual position in table)
    *   \return nb of elements read
    */
     
    int thread_read(int iNb, resource_s *psResource){
     
        int indi;
     
        /*Go in critical section*/
        pthread_mutex_lock(&(psResource->mutex));
        fprintf(psResource->fid, "thread read: critical section in\n");
        /*If the table is not empty*/
        fprintf(psResource->fid, "thread read: position=%d size asked=%d table size=%d\n", psResource->i_pos, iNb, RESOURCE_SIZE);
        if(psResource->i_pos - iNb >= 0){ //ICI, je regarde s'il y a des choses à lire dans le tableau. Si oui, lire, iNb éléments, sinon il faut endormir le thread. i_pos est la position actuelle dans le tableau, cad 0 si la tableau est vide, RESOURCE_SIZE-1 s'il est plein, etc...
            psResource->i_pos -= iNb; //ICI, je dis que j'ai lu des données
            for(indi=0; indi < iNb; ++indi){
                psResource->i_tab[psResource->i_pos - indi] = 0; //Ici, je remets les élements lu à 0
            }
     
            fprintf(psResource->fid, "thread read: nb elem readed=%d, actual position=%d\n", indi, psResource->i_pos);
            fprintf(psResource->fid, "thread read: send signal\n");
            pthread_cond_signal(&(psResource->cond1)); //Ici, je signal au thread producteur que j'ai lu des données et donc que le tableau a de la place libre
            fprintf(psResource->fid, "thread read: critical section out\n");
            pthread_mutex_unlock(&(psResource->mutex));
        }else{
            /*Sleep*/
            fprintf(psResource->fid, "thread read: can t read, sleep\n");
            pthread_cond_wait(&(psResource->cond2), &(psResource->mutex)); //ICI, j'attends que le thread producteur remplisse le tableau
            fprintf(psResource->fid, "thread read: critical section out\n");
            pthread_mutex_unlock(&(psResource->mutex)); /*unlock mutex*/
        }
     
        return iNb;
    }

    Qu'en pensez vous? Est-ce une bonne méthode? Une bonne logique? Auriez-vous fait pareil?
    Est-ce que je peux avoir (avec cette architecture) un blocage (genre les 2 threads attendent la même conditions...).
    En fin, ma derniere question:
    est-ce normal de mettre pthread_cond_wait dans une section critique?
    En effet, dans mon cas, je ne comprends pas pourquoi ça marche, je pensais que ça ferai:

    [dans le thread consommateur]
    1-entrer en section critique [mutex]
    2- si il n'y a rien à lire, pthread_cond_wait
    3- alors, le thread s'endort et l'ordonnanceur passe au thread producteur.
    4- le thread producteur essaye de passer en section critique, mais il ne peux pas, car mutex n'a pas été relaché auparavant.

    Bon, vu que le programme fonctionne, ce que je dis ci dessus est faux, mais pourquoi?

    Ca fait beaucoup de questions, j'espère ne pas vous ennuyer avec.
    En tout cas, si ce sujet vous interesse et que vous voulez bien répondre à mes questions, et bien merci beaucoup!

    Cordialement,
    morpheusmg

  2. #2
    Expert Confirmé Sénior Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    septembre 2005
    Messages
    24 064
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : septembre 2005
    Messages : 24 064
    Points : 34 922
    Points
    34 922

    Par défaut

    Normalement, pour une file producteur/consommateur, tu peux utiliser deux sémaphores à la place d'une section critique: Un sémaphore qui compte les objets dans la file, et un qui compte les places vides.

    Dans ce cas, tu auras besoin aussi de deux entiers: Un pour l'index d'écriture et un pour l'index de lecture.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Futur Membre du Club
    Inscrit en
    novembre 2007
    Messages
    59
    Détails du profil
    Informations forums :
    Inscription : novembre 2007
    Messages : 59
    Points : 19
    Points
    19

    Par défaut

    @Médinoc:
    Merci pour ta réponse. Je ne me suis pas encore penché sur les sémaphores. Quand je serai à l'aise avec les mutex, il faudra que j'essaye les sémaphores.

    Sinon, personne n'a de critiques/conseilles sur mon code?

    Par avance merci!

  4. #4
    Membre actif Avatar de fastdeath124
    Homme Profil pro
    Ingénieur sécurité
    Inscrit en
    août 2011
    Messages
    117
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Tunisie

    Informations professionnelles :
    Activité : Ingénieur sécurité

    Informations forums :
    Inscription : août 2011
    Messages : 117
    Points : 194
    Points
    194

    Par défaut

    Si le producteur suit quasiment le même algorithme, je pense qu'il y aura un interblocage :
    Considérons le scénario où le tableau est vide et le consommateur accède en premier à la section critique. Il sera bloqué en attendant que le producteur le libère (ligne 29).
    De son coté, le producteur ne pourra pas entrer en section critique puisqu'elle est encore réservée par le consommateur (ligne 11).

  5. #5
    Futur Membre du Club
    Inscrit en
    novembre 2007
    Messages
    59
    Détails du profil
    Informations forums :
    Inscription : novembre 2007
    Messages : 59
    Points : 19
    Points
    19

    Par défaut

    @ fastdeath124: Merci de poser cette question, car justement, je me la pose plus ou moins aussi.

    Ce que j'ai compris:
    On suppose le tableau vide et que le consommateur accède en premier à la section critique.

    1] Donc, on est à la ligne 11 et bloque le mutex.

    2] Arrivant à la ligne 15, il teste si le tableau est vide. Dans notre cas, il est vide, donc on va ligne au "else" ligne 26.

    3] On fait ensuite un "pthread_cond_wait".
    De ce que j'ai compris, cette fonction prend en argument le mutex de la section critique, le relâche et demande à l'ordonnanceur de quitter le thread.

    4] Comme le mutex est relâché, alors on peut entrer en section critique du thread producteur, qui écrira dans le tableau.

    5] Comme on remplis le tableau (je suis dans le thread producteur), je fais un pthread_cond_signal, pour dire qu'il y a quelque chose dans le tableau.

    6] De ce que j'ai compris, c'est que pour revenir au thread lecteur (et donc franchir la ligne 29 du pthread_cond_wait), l'ordonnanceur attend que le mutex soit relâché.

    Justement, est ce que mes suppositions 3] et 6] sont vraies?
    a) Est-ce que pthread_cond_wait doit être utilisé à l’intérieur de sa section critique?
    b) Si oui, est-ce que le mutex qu'on lui donne en argument est celui de sa section critique?
    c) Si oui, est-ce que pthread_cond_wait relâche "temporairement" ce mutex?


    Ensuite, je me demande si ce que je dis ensuite est vrai:
    0) on entre dans la fonction maFonction par le thread thread1

    1) on bloque le mutex monMutex

    2) au bout d'un moment, on arrive à pthread_cond_wait(maCondition, monMutex)

    3) si maCondition n'est pas valide, alors la fonction relâche monMutex, et l’ordonnanceur passe à un autre thread (thread2) qui a une section critique def par monMutex

    4) au bout d'un moment, maCondition devient VALIDE et à ce même moment, l'ordonnanceur décide de revenir à maFonction du thread1

    5) alors la fonction pthread_cond_wait ne sera passante QUE SI mon monMutex est relâché (cad qu'on est sortie de la section critique de thread2!)
    Si on n'est pas sortie de la section critique de thread2, alors monMutex est bloqué, et on ne devrait pas passé pthread_cond_wait!).

    Ok, supposons que je sois dans la situation ou monMutex est relâche (car je pense que lorsqu'on entre dans cette fonction, elle relâche monMutex) et que je veuille franchir pthread_cond_wait. Alors pthread_cond_wait re-bloquera monMutex.

    Je ne sais pas si ce que je dis au dessus est vrai.

    Qu'en pensez-vous?

    Par avance merci!!!

  6. #6
    Futur Membre du Club
    Inscrit en
    novembre 2007
    Messages
    59
    Détails du profil
    Informations forums :
    Inscription : novembre 2007
    Messages : 59
    Points : 19
    Points
    19

    Par défaut

    Maintenant que j'ai appris à lire, en relisant http://franckh.developpez.com/tutoriels/posix/pthreads/, je vois:

    En effet, si on regarde le début du corps de la boucle, on peut s'apercevoir que le thread prend le mutex (note de morpheusmg: on entre en section critique!) et se met en attente de la condition(note de morpheusmg: pthread_cond_wait) . En réalité, le thread relâche le mutex aussitôt et le reprend automatiquement lorsque la condition est vraie et qu'il soit réveillé par un autre thread. Lorsque la stock est remplit, la fonction le signale au thread du client courant.
    Donc voici une réponse à ma première question:
    pthread_cond_wait(maCondition, monMutex) relâche temporairement monMutex (monMutex qui définie la section critique!)

    J'avance!!!

    J’espère que mes questions et remarques vous intéressent et vous apprennent des choses!

    En tout cas, si vous avez des réponses à mes questions, n'hésitez pas! De même si vous avez des commentaires sur mon premier post!

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •