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 :

Threads en C


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2023
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2023
    Messages : 4
    Par défaut Threads en C
    Hey,

    Je bloque sur un exercice qui fait appel à des threads et j'aurais quelques questions.
    L'objectif est de faire tracer un carré avec des symboles à différents threads. Et on doit commencer par faire une attente que tous les threads soients prêts avant de démarrer une boucle principale, et je n'arrive pas à le faire en utilisant les conditions posix. L'attente ne fonctionne pas. (voir tentative).
    De plus, il faut ensuite que le thread principal envoie quel symbole afficher et combien de fois et que chaque thread va dès lors entrer en compétition pour effectuer les affichages demandés : tant que le symbole doit être encore affiché, le thread doit l’afficher (une seule fois), décrémenter le nombre d’affichages demandés, puis il doit attendre un délai aléatoire avant de recommencer.
    J'ai cherché et je n'ai pas compris comment faire ?
    Merci d'avance pour l'aide

    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
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
     
    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <stdarg.h>
    #include <stdnoreturn.h>
    #include <pthread.h>
     
     
    #define CHK(op)		do { if ((op) == -1) raler(1, #op); } while (0)
    #define CHKN(op)	do { if ((op) == NULL) raler(1, #op); } while (0)
     
    #define TCHK(op)	do { if ((errno = (op)) > 0) raler(1, #op); } while (0)
     
    noreturn void raler (int syserr, const char *msg, ...)
    {
        va_list ap;
     
        va_start (ap, msg);
        vfprintf (stderr, msg, ap);
        fprintf (stderr, "\n");
        va_end (ap);
     
        if (syserr == 1)
    	perror ("");
     
        exit (1);
    }
     
     
    // ----------------------------------------------------
     
    struct affichage
    {
        char symbole;
        int nb_affichages;
    };
     
    struct carre
    {
        int compteur_cond;  // compteur pour condition 
        int delai_max;      // delai max 
        int n;              // nombre threads
        pthread_cond_t sync;
        pthread_mutex_t verrou;
    };
     
    // les args de chaque thread
    struct arg
    {
        int num_threads;	        // donnée privée au thread
        struct carre *carre;		// données partagées
        struct affichage *affichage;// tableau des affichages à réaliser
    };
     
     
    // retourne un nombre pseudo-aléatoire entre 0 et max (exclu)
    int prandom_number (int max, unsigned int *seed) {
        return max * (rand_r (seed) / ((double) RAND_MAX + 1)) ;
    }
     
    void *afficheur (void *arg) {
        struct arg *a = arg;
        struct carre *carre = a->carre;
        int delai; // délai d'attente aléatoire
        int moi = a->num_threads;  // mon numéro de thread
        int i;
     
        unsigned int seed = moi; // propre au thread + actualisé à chq randr
     
        // Etape 2
        // seed est le numéro du thread
        delai = prandom_number (carre->delai_max, &seed);
        usleep (delai * 1000);	// attente aléatoire en micro-secondes 
     
        pthread_mutex_lock (&carre->verrou);
        // Incrémenter le compteur de threads ayant atteint le point de
        // synchronisation
        carre->compteur_cond++;
     
        // Si tous les threads ne sont pas encore arrivés, 
        // attendre sur la variable conditionnelle
     
        while (carre->compteur_cond < carre->n) {
            pthread_cond_wait (&carre->sync, &carre->verrou);
        }
     
        // Tous les threads sont prêts, débloquer le mutex et continuer
        pthread_mutex_unlock (&carre->verrou);
     
        // Etape 3
        printf ("thread prêt\n");
     
     
        for (i = 0; i<2; i++) {
            printf ("On rentre boucle principale\n");
        }
     
     
     
        return NULL;
    }
     
     
     
    int main(int argc, char *argv[]) {
     
        int delai_max, nb_threads, taille_cotes, i, delai;
        struct carre carre;		// partagé par tous les joueurs
        pthread_t *tid;                 // tableau des id de threads
        struct arg *targ;               // tableau des args des threads
        //unsigned int seed;
     
        // Vérification de tous arguments
        // Affichage sur sortie standard
        if (argc != 4) 
            raler (0, "usage: carre delai_max nb_threads taille_cote");
     
        delai_max = atoi (argv[1]);
        nb_threads = atoi (argv[2]);
        taille_cotes = atoi (argv[3]);
     
     
        // j'ai mis nb_cotes < 1, car on peut pas faire un carré sinon
        if (delai_max <= 0 || nb_threads < 0 || taille_cotes < 1)
    	    raler (0, "argument invalide pour jouer");
     
     
        carre.compteur_cond = 0;
        carre.delai_max = delai_max;
        carre.n = nb_threads;
        TCHK(pthread_cond_init (&carre.sync, NULL));
     
     
        // allocation des tableaus des ids et des args
        CHKN(tid = calloc (nb_threads, sizeof *tid));
        CHKN(targ = calloc (nb_threads, sizeof *targ));
     
     
        // Etape 1 : création des threads
        for (i = 0; i < nb_threads; i++) {
            targ[i].num_threads = i;
            targ[i].carre = &carre;
     
            TCHK(pthread_create (&tid[i], NULL, afficheur, &targ[i]));
        }
     
        // Verrouiller le mutex de la structure carre
        pthread_mutex_lock (&carre.verrou);
     
        // Réinitialiser le compteur de threads
        carre.compteur_cond = 0;
     
        // Envoyer un signal à tous les threads en attente sur 
        // la variable conditionnelle
        pthread_cond_broadcast (&carre.sync);
     
        // Débloquer le mutex de la structure carre
        pthread_mutex_unlock (&carre.verrou);
     
        printf ("debut\n");
     
     
     
     
     
     
        for (i = 0; i < nb_threads; i++) {
    	    TCHK(pthread_join (tid[i], NULL));
        }
     
        TCHK(pthread_cond_destroy(&carre.sync));
     
        free (tid) ;
        free (targ) ;
     
     
        exit (0);
    }

  2. #2
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2023
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2023
    Messages : 4
    Par défaut
    Je précise la fin de l'exercice pour avoir une idée de ce qu'il faut faire :
    Puis entre chaque attente des threads, les autres threads peuvent effectuer leur affichage. Ensuite, le dernier thread qui a affiché un symbole doit finalement réveiller le thread principal pour passer au suivant.
    Lorsque tout a été affiché, le principal dit aux autres de s'arrêter et attend leurs terminaisons. Chaque thread affiche finalement thread terminé avant de s'arrêter

  3. #3
    Expert confirmé
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 599
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 599
    Par défaut
    Salut,

    Commençons par la synchro.

    Les objets servant à la communication doivent être initialisés. Tu as initialisé la cond_var ligne 133, mais il faut aussi initialiser le mutex.

    Ensuite chaque thread va se compter et si le compte n'y est pas va attendre. Le dernier arrivé va bien voir que le compte y est. Mais les autres sont tous bloqués en attente (ligne 86), et personne ne les prévient, ils restent indéfiniment en attente.
    Le dernier arrivé à pu dépasser cette ligne, il doit signaler aux autres qu'il est temps de se réveiller. Un broadcast doit être effectué (par exemple ligne 88).

    Il faut ensuite prévenir le thread principal que tout le monde est prêt (ça peut se faire en utilisant la même cond_var et le même mutex, et un nouveau champs dans carre). Le thread principal, en attente sur la modification de ce champ (il y a wait, donc forcément un signal à envoyer...), va alors voir que c'est le moment. Il va transmettre ses consignes (d'autres champs avec cond_var, mutex), récues par les threads qui devront se mettre d'accord pour gérer le décompte)...

  4. #4
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2023
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2023
    Messages : 4
    Par défaut
    Merci ! Alors j'ai très bien compris la partie sur le broadcast avec les explications de pourquoi mon programme se bloquait indéfiniment. (erreur d"étourderie pour l'initialisation

    Mais je ne suis pas sûr d'avoir tout compris sur la dernière partie. Est-ce que je peux rajouter un booléen int threads_prets; par exemple, qui sera initialement à 0 et passera à 1 quand tous les threads seront prêts.
    Puis rajouter une attente dans le main sur cette condition ? J'ai tenté comme cela :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    struct carre
    {
        int compteur_cond;  // compteur pour condition 
        int delai_max;      // delai max 
        int n;              // nombre threads
        int threads_prets;
        pthread_cond_t sync;
        pthread_mutex_t verrou;
    };
    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
     
        // Envoyer un signal à tous les threads en attente sur 
        // la variable conditionnelle
        pthread_cond_broadcast (&carre->sync);
        // Tous les threads sont prêts, débloquer le mutex et continuer
        pthread_mutex_unlock (&carre->verrou);
     
        // Etape 3
        printf ("thread prêt\n");
     
        carre->threads_prets = 1;
     
        for (i = 0; i<2; i++) {
            printf ("On rentre boucle principale\n");
        }
    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
     
     carre.compteur_cond = 0;
        carre.delai_max = delai_max;
        carre.n = nb_threads;
        carre.threads_prets = 0;
        TCHK(pthread_mutex_init (&carre.verrou, NULL));
        TCHK(pthread_cond_init (&carre.sync, NULL));
     
     
        // allocation des tableaus des ids et des args
        CHKN(tid = calloc (nb_threads, sizeof *tid));
        CHKN(targ = calloc (nb_threads, sizeof *targ));
     
     
        // Etape 1 : création des threads
        for (i = 0; i < nb_threads; i++) {
            targ[i].num_threads = i;
            targ[i].carre = &carre;
     
            TCHK(pthread_create (&tid[i], NULL, afficheur, &targ[i]));
        }
     
        printf ("debut\n");
     
        pthread_mutex_lock (&carre.verrou);
        while (carre.threads_prets != 1) {
            pthread_cond_wait (&carre.sync, &carre.verrou);
        }
        pthread_mutex_unlock (&carre.verrou);
     
        // Consignes du thread principal ...

  5. #5
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2023
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2023
    Messages : 4
    Par défaut
    EDIT : Oups, mettre la maj de carre->threads_prets = 1; dans le mutex pour éviter les problèmes de synchro

  6. #6
    Expert confirmé
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 599
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 599
    Par défaut
    Et le thread principal doit être en attente comme ci-dessous, et il faut lui envoyer un signal pour le réveiller.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
        pthread_mutex_lock( &carre.verrou );
        while ( carre.thread_prets == 0 ) {
            pthread_cond_wait( &carre.sync, &carre.verrou );  // attendre que les threads soient prêts
        }
        pthread_mutex_unlock( &carre.verrou );
        // les threads sont prêts, on continue
     
        // ... décider du nombre et du caractère ...
     
        pthread_mutex_lock( &carre.verrou );
        // ... écrire la demande dans carre ...
        // ... avec peut-être un booléen de plus qui dit que c'est pret ...
        pthread_cond_broadcast( &carre.sync ); // réveiller les threads qui attendaient et se rendent compte d'une tache à faire
        pthread_mutex_unlock( &carre.verrou );

Discussions similaires

  1. Tri multi-threadé
    Par Tifauv' dans le forum C
    Réponses: 8
    Dernier message: 28/06/2007, 09h00
  2. récupérer la valeur de sortie d'un thread
    Par jakouz dans le forum Langage
    Réponses: 3
    Dernier message: 31/07/2002, 11h28
  3. Programmer des threads
    Par haypo dans le forum C
    Réponses: 6
    Dernier message: 02/07/2002, 13h53
  4. Réponses: 5
    Dernier message: 12/06/2002, 15h12
  5. [Kylix] Pb de Thread !!
    Par Anonymous dans le forum EDI
    Réponses: 1
    Dernier message: 25/04/2002, 13h53

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