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 :

Comportement de thread du tuto Developpez.com


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Nouveau candidat au Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2019
    Messages
    1
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Février 2019
    Messages : 1
    Par défaut Comportement de thread du tuto Developpez.com
    Bonjour à tous,

    J'ai étudié le tutoriel sur les thread en C (https://franckh.developpez.com/tutor...osix/pthreads/) et j'ai remarqué des comportements curieux.
    Quand je lance le programme sur le dernier exemple (qui limite la charge CPU), avec les threads fn_clients
    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
     
    /* Fonction pour les threads des clients. */
    static void * fn_clients (void * p_data)
    {
       int nb = (int) p_data;
     
       while (1)
       {
          int val = get_random (6);
     
     
          psleep (get_random (3));
     
          /* Debut de la zone protegee. */
          pthread_mutex_lock (& store.mutex_stock);
     
          if (val > store.stock)
          {
             pthread_cond_signal (& store.cond_stock);
             pthread_cond_wait (& store.cond_clients, & store.mutex_stock);
          }
     
          store.stock = store.stock - val;
          printf (
             "Client %d prend %d du stock, reste %d en stock !\n",
             nb, val, store.stock
          );
     
          pthread_mutex_unlock (& store.mutex_stock);
          /* Fin de la zone protegee. */
       }
     
       return NULL;
    }
    la sortie affichée montre des clients 0, 1, 2, 3, 4 qui s'enchainent aléatoirement pour prendre dans le thread stock, ce qui me semble attendu.
    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
     
    /* Fonction pour le thread du magasin. */
    static void * fn_store (void * p_data)
    {
       while (1)
       {
          /* Debut de la zone protegee. */
          pthread_mutex_lock (& store.mutex_stock);
          pthread_cond_wait (& store.cond_stock, & store.mutex_stock);
     
          store.stock = INITIAL_STOCK;
          printf ("Remplissage du stock de %d articles !\n", store.stock);
     
          pthread_cond_signal (& store.cond_clients);
          pthread_mutex_unlock (& store.mutex_stock);
          /* Fin de la zone protegee. */
       }
     
       return NULL;
    }
    Puis passé un certain délai, l'enchainement aléatoire ne se passe plus, il y a juste un thread client X qui pioche dans le stocke jusqu'à épuisement, puis c'est le tour d'une autre thread client Y d'aller piocher.
    Pourquoi ce comportement s'intalle au fil du temps ?

    De plus, quand on retire la ligne de la fonction client
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    psleep (get_random (3));
    le code finit par se bloquer tout seul sans cracher (ce qui me fait penser à un Dead Lock évoqué dans le tuto) en ayant justement l'appel du client X qui pioche jusqu'à 0 stock puis c'est le client Y.

  2. #2
    Membre actif
    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 23
    Par défaut
    Salut,

    1. Le store est en attente du Mutex (pthread_mutex_lock)
    2. Le client qui a le Mutex a val > stock.
    3. Le client appele pthread_cond_signal dans le vide car le store n'est pas en attente de la condition
    4. Le client appele pthread_cond_wait ce qui libère le Mutex.
    5. Le store prend le mutex par pthread_mutex_lock
    6. Le store appele pthread_cond_wait, ce qui libère le mutex, mais ne suffit pas à débloquer le client en attente par pthread_cond_wait.
    => Blocage

    Solution:
    Dans le store, appeler pthread_cond_signal avant l'appel à pthread_cond_wait.

  3. #3
    Membre très actif
    Avatar de sambia39
    Homme Profil pro
    No Comment
    Inscrit en
    Mai 2010
    Messages
    548
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : No Comment
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Mai 2010
    Messages : 548
    Par défaut
    Bonjour,

    

Oui il y a effectivement blocage a cause d'un thread bloqué et cela est dû aux différentes tentatives d'appel sur le mutex qui est déjà verrouillé.
    Et comme le thread "x" qui détenait le mutex est bloqué, il n'est donc plus possible de déverrouiller le mutex ; résultat : le programme reste bloqué sans se crasher.

    Cependant, j’attire tout de même l'attention sur une possible "race condition", car à aucun moment, on ne contrôle pas la valeur retour que renvoient les fonctions suivantes (pthread_mutex_lock, pthread_mutex_unlock etc..) . Et si par exemple pthread_mutex_lock ne peut pas acquérir le mutex pour x raisons, l'ensemble de la fonction va systématiquement causer une "race condition" et fatalement, le programme aura un comportement indéterminé : il serait donc préférable de vérifier la valeur retour de ces fonctions de synchronisation et prendre les mesures adaptées et ne pas faire confiance à ces fonctions de manière aveugle.

    Ceci dit, je ne comprends pas pourquoi il y a deux conditions en plus qu'il peut y avoir un autre problème : celui du réveil des threads. Je m'explique : lorsque l'on souhaite réveiller tous les threads qui surveillent la même condition dans un programme multi-threader, il est préférable d'employer pthread_cond_broadcast surtout que l'on ne parle pas de deux threads, mais de plusieurs, car la fonction pthread_cond_broadcast permettra ce que plusieurs threads puissent poursuivre leur tâche respectives et ne pas être dans l'attente. Mais bon, ceci dit pthread_cond_broadcast ou pthread_cond_signal dans les deux cas normalement aucune erreur ne devrait se produire si aucun thread n’est en attente.

    À bientôt.

  4. #4
    Membre actif
    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 23
    Par défaut
    Et fonctionnellement parlant, pour éviter d'avoir un stock négatif, le code du client peut être:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
          while (val > store.stock)
          {
             if(pthread_cond_signal (& store.cond_stock) != 0) printf("BOGUS\n");
             if(pthread_cond_wait (& store.cond_clients, & store.mutex_stock) != 0) printf("BOGUS\n");
          }
    Car le client peut très bien se ré-exécuter avant que le store n'ait remplie le stock.
    Le choix du thread s'exécutant étant laissé à la charge de l'OS et de sa politique d'ordonnancement.

Discussions similaires

  1. boite a onglet du tuto developpez.com
    Par nine dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 28/12/2012, 21h50
  2. problème avec pied de page [Tuto de developpez.com]
    Par developpeur_mehdi dans le forum Mise en page CSS
    Réponses: 4
    Dernier message: 15/01/2007, 16h26
  3. Réponses: 4
    Dernier message: 13/02/2006, 11h34

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