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 :

thread - variable partagée non souhaitée


Sujet :

C

  1. #1
    Membre à l'essai
    Profil pro
    étudiant ingénieur
    Inscrit en
    Juin 2010
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : étudiant ingénieur

    Informations forums :
    Inscription : Juin 2010
    Messages : 37
    Points : 12
    Points
    12
    Par défaut thread - variable partagée non souhaitée
    Bonjours,
    J'ai un thread qui exécute ceci :

    Edition : ajout du 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
    void *task_write_in_buffer (void *p)
    {
        struct data *p_data = p;
        struct shared *psh = p_data->psh;
        sFIFO *pTempfifo = psh->pfifo;
        char buff[40];
        int i = 0;
     
        if(p != NULL )
        {
            while(1)
            {
                sprintf(buff,"%s : %d\r\n", p_data->sid,i);
     
                pthread_mutex_lock (&psh->mut);
     
                    fifoenter(pTempfifo,buff);
     
                pthread_cond_signal (&psh->synchro);
                pthread_mutex_unlock (&psh->mut);
     
                i++;
     
                msleep (500);
            }
        }
        return NULL;
    }
            }
    J'ai une fifo partagée entre plusieurs threads, celui ci dessus qui y ajoute une chaîne de caractère.
    Et un autre qui dépile et affiche le contenue de la pile.

    Je me suis rendu compte que si je crée deux thread qui exécute le code ci-dessus, la variable "i" est partagé entre eux

    Comment ce fait t'il que i soit partagé entre les deux thread et comment ce fait t'il qu'il n'est pas était décrémenté (cf ci-dessous en vert) ?

    Sortie du thread qui depile la fifo :
    task A : 1
    Task C : 2
    Task C : 3
    task A : 4
    Task C : 5
    task A : 6
    Task C : 7
    Task C : 7
    task A : 8
    Task C : 9
    Task C : 10

    Merci d'éclairer ma lanterne

  2. #2
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut
    Bonjour,

    Il est difficile de répondre alors qu'on ne sait pas comment tu as déclaré i ni même comment tu l'as transmis à la fonction qui effectue le traitement.

    Mais je suppose que i est une variable globale ?

  3. #3
    Membre expert
    Avatar de Metalman
    Homme Profil pro
    Enseignant-Chercheur
    Inscrit en
    Juin 2005
    Messages
    1 049
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Enseignant-Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 049
    Points : 3 532
    Points
    3 532
    Par défaut
    Je rajouterais juste à la remarque et aux questions de Neckara : n'oublie pas que les threads travaillent "avec" le processus dans le même AS !
    Du coup les variables globales et la mémoire sont partagées !
    --
    Metalman !

    Attendez 5 mins après mes posts... les EDIT vont vite avec moi...
    Les flags de la vie : gcc -W -Wall -Werror -ansi -pedantic mes_sources.c
    gcc -Wall -Wextra -Werror -std=c99 -pedantic mes_sources.c
    (ANSI retire quelques fonctions comme strdup...)
    L'outil de la vie : valgrind --show-reachable=yes --leak-check=full ./mon_programme
    Et s'assurer que la logique est bonne "aussi" !

    Ma page Developpez.net

  4. #4
    Membre à l'essai
    Profil pro
    étudiant ingénieur
    Inscrit en
    Juin 2010
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : étudiant ingénieur

    Informations forums :
    Inscription : Juin 2010
    Messages : 37
    Points : 12
    Points
    12
    Par défaut
    Ah oui ^^
    J'avais mit le minimum de code pour pas surcharger le poste

    i est une variable locale, c'est bien là le problème.

    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
    void *task_write_in_buffer (void *p)
    {
        struct data *p_data = p;
        struct shared *psh = p_data->psh;
        sFIFO *pTempfifo = psh->pfifo;
        char buff[40];
        int i = 0;
     
        if(p != NULL )
        {
            while(1)
            {
                sprintf(buff,"%s : %d\r\n", p_data->sid,i);
     
                pthread_mutex_lock (&psh->mut);
     
                    fifoenter(pTempfifo,buff);
     
                pthread_cond_signal (&psh->synchro);
                pthread_mutex_unlock (&psh->mut);
     
                i++;
     
                msleep (500);
            }
        }
        return NULL;
    }

  5. #5
    Membre confirmé
    Avatar de deletme
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    257
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2011
    Messages : 257
    Points : 519
    Points
    519
    Par défaut
    Salut,

    Après une lecture rapide du code, ta variable i est utilisée hors de la zone critique, donc potentiellement, les deux threads peuvent y accéder "simultanément". Essayes en passant le i++ avant de libérer le sémaphore.

    Cdlt, dM
    "Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live."
    - Martin Golding
    Traduction obligatoire : "Toujours écrire du code en gardant en tête que le mec qui en assurera la maintenance est un psychopathe violent qui connait votre adresse"

  6. #6
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Je suis étonné du comportement. La variable i est une variable locale non statique donc j'aurais tendance à penser que chaque thread en possède sa propre instance.

    Ton code ne permet pas de reproduire le problème, ce serait gentil d'en fourni un.

    Perso, j'ai essayé de reproduire le soucis avec le code suivant mais il ne reproduit rien...
    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
    #include <stdlib.h>
    #include <stdio.h>
    #include <stdint.h>
    #include <windows.h>
     
     
    #include "pthread.h"
     
    static pthread_mutex_t mutex_screen = PTHREAD_MUTEX_INITIALIZER;
     
    void *task(void *p)
    {
        int i = 0;
     
        while(1)
        {
            pthread_mutex_lock(&mutex_screen);
            printf("%s = %d\n", p, i);
            pthread_mutex_unlock(&mutex_screen);
            i++;
            Sleep(1000);
        }
        return NULL;
    }
    int main(void)
    {
        pthread_t thread_1;
        pthread_t thread_2;
     
        pthread_create(&thread_1, NULL, task, (void*)"T1");
        pthread_create(&thread_2, NULL, task, (void*)"T2");
     
        pthread_join(thread_1, NULL);
        pthread_join(thread_2, NULL);
        return 0;
    }

  7. #7
    Membre éclairé
    Profil pro
    Ingénieur sécurité
    Inscrit en
    Février 2007
    Messages
    574
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : Etats-Unis

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

    Informations forums :
    Inscription : Février 2007
    Messages : 574
    Points : 751
    Points
    751
    Par défaut
    Citation Envoyé par Bktero Voir le message
    Je suis étonné du comportement. La variable i est une variable locale non statique donc j'aurais tendance à penser que chaque thread en possède sa propre instance.
    Oui, c'est exact. Chaque thread dispose de sa propre stack, seule la "heap", les librairies partagees et les zones statiques (.text, .rodata, ...) sont partagees entre le parent et les thread enfants. Ici i est declaree sur la "stack", donc n'est accessible qu'au thread local.

    J'ai regarde tres rapidement, mais pthread_cond_signal (&psh->synchro) doit se placer apres le realease de la mutex. Car pthread_cond_wait() dans le thread concommant ta FIFO va relacher la mutex. Du coup ton thread consommateur va relacher la mutex lockee par le thread producteur. C'est un comportement indefini normallement (seul un thread ayant locke la mutex peut la relacher).

    Je sais pas si ton probleme vient de la, mais ca enleve deja un probleme potentiel.

  8. #8
    Membre à l'essai
    Profil pro
    étudiant ingénieur
    Inscrit en
    Juin 2010
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : étudiant ingénieur

    Informations forums :
    Inscription : Juin 2010
    Messages : 37
    Points : 12
    Points
    12
    Par défaut
    J'ai regarde tres rapidement, mais pthread_cond_signal (&psh->synchro) doit se placer apres le realease de la mutex. Car pthread_cond_wait() dans le thread concommant ta FIFO va relacher la mutex. Du coup ton thread consommateur va relacher la mutex lockee par le thread producteur. C'est un comportement indefini normalement (seul un thread ayant locke la mutex peut la relacher).

    Je sais pas si ton problème vient de la, mais ca enleve deja un problème potentiel.
    Étrange, sur les tuto de Franck Hecht et emmanuel-delahaye
    http://franckh.developpez.com/tutoriels/posix/pthreads/
    http://emmanuel-delahaye.developpez....-threads-c/#LV

    ainsi que dans le manuel de référence ecos (l'os embarqué que j'utilise)
    http://ecos.sourceware.org/docs-2.0/...variables.html

    Tous indique qu'il faut envoyer le signal puis relacher le mutex

  9. #9
    Membre éclairé
    Profil pro
    Ingénieur sécurité
    Inscrit en
    Février 2007
    Messages
    574
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : Etats-Unis

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

    Informations forums :
    Inscription : Février 2007
    Messages : 574
    Points : 751
    Points
    751
    Par défaut
    Citation Envoyé par silenteagle Voir le message
    Tous indique qu'il faut envoyer le signal puis relacher le mutex
    Je n'ai pas verifie les sources que tu proposes, mais j'ai verifie dans "The Linux Programming Interface" de Michael Kerrisk (ma bible ) , le relachement de la variable conditionnelle se fait bien apres l'unlock:

    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
     
    The code in the producer threads is the same as before, except that we add a call to
    pthread_cond_signal():
    s = pthread_mutex_lock(&mtx);
    if (s != 0)
        errExitEN(s, "pthread_mutex_lock");
        avail++;	/* Let consumer know another unit is available */
    s = pthread_mutex_unlock(&mtx);
    if (s != 0)
        errExitEN(s, "pthread_mutex_unlock");
    s = pthread_cond_signal(&cond);	/* Wake sleeping consumer */
    if (s != 0)
        errExitEN(s, "pthread_cond_signal");
     
    Before considering the code of the consumer, we need to explain pthread_cond_wait() in greater detail. We noted earlier that a condition variable always has an associated mutex. Both of these objects are passed as arguments to pthread_cond_wait(), which performs the following steps:
        * unlock the mutex specified by mutex;
        * block the calling thread until another thread signals the condition variable cond; and
        * relock mutex.
     
    The pthread_cond_wait() function is designed to perform these steps because, normally, we access a shared variable in the following manner:
    s = pthread_mutex_lock(&mtx); if (s != 0)
        errExitEN(s, "pthread_mutex_lock");
    while (/* Check that shared variable is not in state we want */)
        pthread_cond_wait(&cond, &mtx);
    /* Now shared variable is in desired state; do some work */
    s = pthread_mutex_unlock(&mtx); if (s != 0)
        errExitEN(s, "pthread_mutex_unlock");
    Si Kerrisk decrit bien ce que fait pthread_cond_wait(), mettre pthread_cond_signal() avant le release du lock provoque un effet de bord decrit dans mon poste precedent.

    Je sais pas ce qui est exact ici, mais je n'ai jamais eu de soucis avec le code precedent.
    Je ne dis pas que c'est le probleme avec ton code cependant, et j'espere que je t'envoie pas sur la mauvaise route...

  10. #10
    Membre confirmé
    Avatar de deletme
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    257
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2011
    Messages : 257
    Points : 519
    Points
    519
    Par défaut
    Salut,

    Possèdes tu le code de fifoenter ? Parce qu'à première vue, l'affichage
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    task A : 1
    Task C : 2
    Task C : 3
    task A : 4
    Task C : 5
    task A : 6
    Task C : 7
    Task C : 7
    task A : 8
    Task C : 9
    Task C : 10
    devrait commencer à 0 non ?
    "Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live."
    - Martin Golding
    Traduction obligatoire : "Toujours écrire du code en gardant en tête que le mec qui en assurera la maintenance est un psychopathe violent qui connait votre adresse"

  11. #11
    Membre à l'essai
    Profil pro
    étudiant ingénieur
    Inscrit en
    Juin 2010
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : étudiant ingénieur

    Informations forums :
    Inscription : Juin 2010
    Messages : 37
    Points : 12
    Points
    12
    Par défaut
    le voici :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    int fifoenter(sFIFO * this, void *next)
    {
        if (this->Ffc == this->Max)
        {
            return (0);
        }
        else
        {
            this->table[this->Ecr] = next;
            this->Ffc++;
            this->Ecr = (this->Ecr + 1) % this->Max;
            return (1);
        }
    }

  12. #12
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    this->table[this->Ecr] = next;
    Ceci va stocker dans la fifo l'adresse du tableau buff de task_write_in_buffer() et non pas le contenu. Autrement dit, tous les éléments dans la fifo font référence au même message : le dernier qui a été écrit dans le buff. Le thread de lecture affiche toujours le dernier message qui a été mis dans buff et qui dépend du moment où il est lu.

    C'est pourquoi, on ne trouve pas l'affichage de i==0 : Le thead A a écrit dans son buff "task A : 0" puis "task A : 1" et à ce moment tous les éléments du fifo qui ont été écrits font référence à "task A : 1" et le thread de lecture a affiché le premier élément de la fifo qui fait référence (comme le deuxième) à "task A : 1" .

    C'est aussi pourquoi, on trouve deux fois "Task C : 7" : il suffit que le thread de lecture lise deux fois avant qu'une nouvelle écrirure soit faite dans le buff du thread C
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

Discussions similaires

  1. Réinitialisation de variable non souhaitée
    Par Zebulon777 dans le forum Général JavaScript
    Réponses: 19
    Dernier message: 18/02/2015, 15h31
  2. Réponses: 6
    Dernier message: 22/10/2009, 17h08
  3. threads et variables partagées
    Par Mr_Brown dans le forum Langage
    Réponses: 3
    Dernier message: 25/04/2007, 15h30
  4. [debutant]threads - variables partagées.
    Par nivose110 dans le forum Concurrence et multi-thread
    Réponses: 1
    Dernier message: 18/01/2006, 06h34
  5. Variables javascript non correctement définies
    Par LLaurent dans le forum XMLRAD
    Réponses: 5
    Dernier message: 11/05/2004, 12h39

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