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 :

Utilisation des Threads


Sujet :

C

  1. #1
    Membre du Club
    Femme Profil pro
    Étudiant
    Inscrit en
    Mars 2023
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 23
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2023
    Messages : 9
    Par défaut Utilisation des Threads
    Bonjour,

    Je reviens encore une fois vers vous pour vous demander de l'aide. Je bloque sur un sujet qui utilise les threads et je précise que c'est la première fois que je les utilise de façon concrète.

    L'objectif est de simuler le fonctionnement d’un jeu dans lequel n threads utilisent chacun un dé pour tirer un nombre aléatoire.
    Une fois les dés tirés, un des threads (pas toujours le même) joue le rôle d’arbitre pour désigner le vainqueur, c’est-à-dire celui qui a tiré le plus grand nombre. S’il y a égalité, l’arbitre indique aux joueurs ceux qui doivent à nouveau s’affronter, et tous les joueurs participent ou regardent le nouveau tirage, qu’un nouveau thread arbitrera.
    Lorsqu’un vainqueur est enfin trouvé, le thread principal est averti. Dès lors, le thread principal peut lancer une nouvelle partie ou ordonner aux n threads de s’arrêter.
    Il y a quelques contraintes comme pas de variables globales.

    J'ai plusieurs questions. Mais tout d'abord, comme on ne peut passer qu'un seul argument dans la création d'un thread, j'ai pensé à passer par une structure mais je n'ai pas trouvé comment la réaliser pour envoyer l'id du thread correspondant. De même, j'ai tenté de créer un tableau de scores pour savoir quel thread a tiré quelle valeur et les comparer. Mais je bloque pour gérer les cas d'égalité et de même forcer les threads à refaire des tirages s'il y a égalité entre ces derniers. Je suis un peu perdue et je pense que d'autres erreurs ont du se glisser.

    Je mets ce que j'ai commencé à faire. Merci d'avance

    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
     
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <pthread.h>
    #include <time.h>
     
    void raler (const char* const msg) 
    {
    	perror (msg);
    	exit(1);
    }
     
    typedef struct {
        int nb_faces;
        int *ids;
        int *scores;
    } t_info;
     
    pthread_barrier_t barriere_tirage, barriere_decision;
     
     
    void *arbitre(void *arg) 
    {
        t_info *info = arg;
        int vainqueur;
        int max_score = 0;
     
        for (int j = 0; j < n; j++) 
        {
            if (info->scores[j] > max_score) 
            {
                max_score = info->scores[j];
                vainqueur = j;
            } else if (info->scores[j] == max_score)
            {
                // gèrer les cas d'égalité ???
            }
        }
     
        if (egalité)
            printf("arbitre %i egalité %", ids.., );
     
        if (vainqueur)
            printf("arbitre %i egalité %", ids.., vainqueur);
     
        // attente des joueurs pour un nouveau tirage
        pthread_barrier_wait(&barriere_decision); 
     
        pthread_exit(NULL);
    }
     
     
    void *joueur(void *arg) 
    {
        t_info *info = arg;
     
        // initialisation de la graine pour rand_r
        //PROBLEME POUR ID THREAD
        unsigned int seed = info->ids; 
     
        // attente que tous les joueurs soient prêts à tirer
        pthread_barrier_wait(&barriere_tirage); 
     
        // tirage d'une face aléatoire du dé
        int face = rand_r(&seed) % info->nb_faces + 1; 
     
        scores[ids] = face;
     
        printf ("thread %i tire %i",info->ids, face);
     
        pthread_exit(NULL);
    }
     
     
    int main(int argc, char *argv[]) {
     
        if (argc != 5) 
        {
            fprintf(1, "Usage: %s faces delai n p\n", argv[0]);
            exit (1);
        }
     
        t_info info;
     
        info.nb_faces = atoi(argv[1]);
        int delai = atoi(argv[2]);
        int n = atoi(argv[3]);
        int p = atoi(argv[4]);
     
        // pour la génération de nombres pseudo-aléatoires
        struct timespec ts;
        clock_gettime(CLOCK_MONOTONIC, &ts);
        unsigned int seed = ts.tv_nsec ^ ts.tv_sec;
        unsigned int* seedp = &seed;
        srand_r(*seedp, &rand_state);
     
        // allocation du tableau des threads
        pthread_t *threads = malloc(n * sizeof(pthread_t));
        if (threads == NULL)
            raler ("Erreur malloc");
     
        // allocation du tableau des identifiants des joueurs
        info.ids = malloc(n * sizeof(int));
        if (info.ids == NULL)
            raler ("Erreur malloc");
     
        info.scores = malloc(n * sizeof(int));
        if (info.scores == NULL)
            raler ("Erreur malloc");
     
     
        for (int i = 0; i < n; i++) 
                info.ids[i] = i;
                info.scores[i] = 0;
     
        for (int partie = 0, partie < p; partie++)
        { 
            printf ("debut partie %i\n", p);
     
            // initialisation de la barrière pour le tirage et la décision
            pthread_barrier_init(&barriere_tirage, NULL, n); 
            pthread_barrier_init(&barriere_decision, NULL, n+1); 
     
            for (int i = 0; i < n-1; i++) 
            {
                // création des threads joueurs
                pthread_create(&threads[i], NULL, joueur, &info);
                if (errno > 0);
                    raler ("pthread_create"); 
            }
     
            // création du thread arbitre (doit être différent)
            // à chaque fois dont PROBLEME
            pthread_create(&threads[n-1], NULL, arbitre, &info); 
            if (errno > 0);
                raler ("pthread_create");
     
            for (int i = 0; i < n; i++) 
            {
                pthread_join(threads[i], NULL); // attente de la fin des threads
                if (errno > 0);
                    raler ("pthread_join");
            }
     
            // destructions des deux barrières
            pthread_barrier_destroy(&barriere_tirage); 
            pthread_barrier_destroy(&barriere_decision); 
     
            printf ("fin partie %i\n", p);
        }
     
        printf ("fin du jeu");
     
        free(info.ids); // libération du tableau des identifiants des joueurs
        free(threads); // libération du tableau des threads
     
        return 0;
    }

  2. #2
    Membre du Club
    Femme Profil pro
    Étudiant
    Inscrit en
    Mars 2023
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 23
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2023
    Messages : 9
    Par défaut
    J'ai corrigé les erreurs bêtes mais je bloque encore.

    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
    181
    182
    183
    184
    185
    186
    187
    188
     
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <pthread.h>
    #include <time.h>
    #include <errno.h>
     
    void raler (const char* const msg) 
    {
    	perror (msg);
    	exit(1);
    }
     
    typedef struct {
        int nb_faces;
        int delai;
        int nb_joueurs;
        int id_thread;
        int id_arbitre;
        int *ids;
        int *scores;
    } t_info;
     
    pthread_barrier_t barriere_tirage, barriere_decision;
     
    int random_number (int max_value) 
    {
        int random_number;
        srand(time(NULL)); // initialisation du générateur de nombres aléatoires
        random_number = rand() % (max_value); 
        return random_number;
    }
     
     
    void *joueur(void *arg) 
    {
        t_info *info = arg;
     
        printf ("Rentre thread joueur");
     
        // initialisation de la graine pour rand_r
        //PROBLEME POUR ID THREAD
        unsigned int seed = info->id_thread; 
     
        // attente que tous les joueurs soient prêts à tirer
        pthread_barrier_wait(&barriere_tirage); 
     
        // tirage d'une face aléatoire du dé
        int face = rand_r(&seed) % info->nb_faces + 1; 
     
        info->scores[info->id_thread] = face;
     
        printf ("thread %i tire %i", info->id_thread, face);
     
        pthread_exit(NULL);
    }
     
     
    void *arbitre(void *arg) 
    {
        t_info *info = arg;
     
        int vainqueur;
        int max_score = 0;
        int nb_max = 1;
        int indices[info->nb_joueurs];
     
        for (int j = 0; j < info->nb_joueurs; j++) 
        {
            if (info->scores[j] > max_score) 
            {
                max_score = info->scores[j];
                vainqueur = j;
                nb_max = 1;
            } else if (info->scores[j] == max_score)
            {
                indices[nb_max] = j;
                nb_max++;
            }
        }
     
        // un gagnant
        if (nb_max == 1)
        {
            printf("arbitre %i egalité %i", info->id_arbitre, vainqueur);
        } else if (nb_max != 1) // cas d'égalité
        {
            printf("arbitre %i egalité ", info->id_arbitre);
            for (int j = 0; j < nb_max; j++)
            {
                printf ("%i", indices[j]);
     
                //pthread_create(&threads[indices[j]], 
                //NULL, joueur, &info);
            }
            printf ("\n");
        }
     
        // attente des joueurs pour un nouveau tirage
        pthread_barrier_wait(&barriere_decision); 
     
        pthread_exit(NULL);
    }
     
    int main(int argc, char *argv[]) {
     
        if (argc != 5) 
        {
            fprintf(stderr, "Usage: %s faces delai n p\n", argv[0]);
            exit (1);
        }
     
        t_info info;
     
        info.nb_faces = atoi(argv[1]);
        info.delai = atoi(argv[2]);
        info.nb_joueurs = atoi(argv[3]);
        int p = atoi(argv[4]);
     
        // allocation du tableau des threads
        pthread_t *threads = malloc(info.nb_joueurs * sizeof(pthread_t));
        if (threads  == NULL)
            raler ("Erreur malloc");
     
        // allocation du tableau des identifiants des joueurs
        info.ids = malloc(info.nb_joueurs * sizeof(int));
        if (info.ids == NULL)
            raler ("Erreur malloc");
     
        info.scores = malloc(info.nb_joueurs * sizeof(int));
        if (info.scores == NULL)
            raler ("Erreur malloc");
     
     
        for (int i = 0; i < info.nb_joueurs; i++)
        { 
                info.ids[i] = i;
                info.scores[i] = 0;
        }
     
        for (int partie = 0; partie < p; partie++)
        { 
            printf ("debut partie %i\n", partie);
     
            // initialisation de la barrière pour le tirage et la décision
            pthread_barrier_init(&barriere_tirage, NULL, info.nb_joueurs); 
            pthread_barrier_init(&barriere_decision, NULL, info.nb_joueurs+1); 
     
            for (int i = 0; i < info.nb_joueurs; i++) 
            {
                // création des threads joueurs
                info.id_thread = info.ids[i];
                pthread_create(&threads[i], NULL, joueur, &info);
                if (errno > 0)
                    raler ("pthread_create"); 
            }
     
            // création du thread arbitre (doit être différent)
            // à chaque fois dont PROBLEME
     
            int id_arbitre = random_number (info.nb_joueurs);
     
            pthread_create(&threads[id_arbitre], NULL, arbitre, &info); 
            if (errno > 0)
                raler ("pthread_create");
     
            for (int i = 0; i < info.nb_joueurs; i++) 
            {
                pthread_join(threads[i], NULL); // attente de la fin des threads
                if (errno > 0)
                    raler ("pthread_join");
            }
     
            // destructions des deux barrières
            pthread_barrier_destroy(&barriere_tirage); 
            pthread_barrier_destroy(&barriere_decision); 
     
            printf ("fin partie %i\n", partie);
        }
     
        printf ("fin du jeu");
     
        free(info.ids); // libération du tableau des identifiants des joueurs
        free(threads); // libération du tableau des threads
     
        return 0;
    }

  3. #3
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 811
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 811
    Billets dans le blog
    1
    Par défaut
    Bonjour

    J'aime bien ta façon de coder. Un peu malhabile mais tu tentes de faire propre et ça c'est bien.
    Quelques remarques générales
    • je suis content qu'il te soit imposé pas de globales. C'est en effet la meilleure façon de faire (chaque fonction est bien indépendante et peut s'utiliser n'importe quand, ce qui est le but général d'une fonction)
    • tu devrais prendre l'habitude d'utiliser le type "size_t". Il a été fait exprès pour les tailles de tableaux et peut donc remplacer le "int" en mieux.
    • si l'allocation 5 échoue, et que tu quittes, il te faut quand-même nettoyer les 4 autres qui, elles, ont réussi. C'est pour ça qu'on appelle ça une "gestion" des erreurs... parce qu'il faut "gérer".
    • concernant les allocations justement, c'est à la fois bien (tu ne réserves que ce qui est nécessaire) et à la fois pas bien (il faut les gérer). Tu as cependant tout à fait le droit de "décider" de remplacer un tableau dynamique par un tableau statique. Si tu dois gérer des "trucs" (threads, joueurs, scores) tu as tout à fait le droit de partir de l'hypothèse qu'il n'y en aurajamais plus de "N". Tu définis ensuite N a une valeur que tu juges assez grande et tu définis ensuite pthread_t threads[N]. Avantage: tu ne te fais plus chier avec tes allocations ; inconvénient: tu dois définir N assez grand pour (statistiquement) avoir toujours assez de thread donc fatalement tu perds de la place et il existe toujours un risque (statistiquement inverse) que N ne soit, dans certains cas extrèmes, pas suffisant. C'est ce qu'on appelle "probabilité de risque/coût de développement pour y faire face". Toutefois concernant la "place perdue" ce n'est pas si dramatique car vu ces petites valeurs ça reste négligeable (entre réserver 50 ids ou réserver 500 ids franchement...) et en plus l'OS fait lui-aussi une optimisation équivalente c'est à dire que même quand tu fais de l'allocation dynamique de (par exemple 150), l'OS réserve de son côté un espace plus grand pour les éventuelles allocations suivantes. Donc dans tous les cas il y a toujours perte de place.
    • l'initialisation d'une graine aléatoire se fait "une fois" (sens principal du verbe "initialiser") et non pas à chaque tirage. La graine c'est le "point de départ" qui permet ensuite n tirages. Son but est de pouvoir générer une séquence de tirages bien précise (si on veut faire des recherches). Généralement on la fait dans le main() (ben oui, un truc qui ne doit se faire qu'une fois se fait dans une fonction qui n'est exécutée qu'une fois)
    • random_number = rand() % (max_value) sérieux??? Moui pourquoi pas. Mais moi j'aurais mis plus de parenthèses pour être certain que "max_value" sera bien isolée du reste. random_number = rand() % ((((max_value)))) c'est quand-même bien plus sûr... Les parenthèses servent à prioriser des opérations, pas des valeurs!!!


    Pour tes soucis d'égalité et de "retirage" ça se programme. Si par exemple le thread a une fonction "tirage()" bien indépendante, rien n'interdit alors de la lui faire appeler plusieurs fois si besoin...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  4. #4
    Membre du Club
    Femme Profil pro
    Étudiant
    Inscrit en
    Mars 2023
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 23
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2023
    Messages : 9
    Par défaut
    J'ai pris en compte les remarques.

    Mais je bloque toujours sur le point de la fonction retirage().

    Si par exemple, on créé nos n threads joueurs, ils vont tous jouer et tirer un nombre.
    Puis le thread arbitre va chercher le vainqueur ou les égalités, je ne vois pas comment on peut faire pour demander à certains threads en particulier de retirer et d'autres juste d'observer.
    C'est pour ça que j'ai essayé de repasser par pthread_create mais ça ne fonctionne pas, car je ne connais pas les threads.
    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
     
    void *joueur(void *arg) 
    {
        t_info *info = arg;
     
        printf ("Rentre thread joueur");
     
        // attente que tous les joueurs soient prêts à tirer
        pthread_barrier_wait(&barriere_tirage); 
     
        // tirage d'une face aléatoire du dé
        int face = rand_r(&info->seed) % info->nb_faces + 1; 
     
        info->scores[info->id_thread] = face;
     
        printf ("thread %i tire %i", info->id_thread, face);
     
        pthread_exit(NULL);
    }
     
     
    void *arbitre(void *arg) 
    {
        t_info *info = arg;
     
        int vainqueur;
        int max_score = 0;
        int nb_max = 1;
        int indices[info->nb_joueurs];
     
        for (int j = 0; j < info->nb_joueurs; j++) 
        {
            if (info->scores[j] > max_score) 
            {
                max_score = info->scores[j];
                vainqueur = j;
                nb_max = 1;
            } else if (info->scores[j] == max_score)
            {
                indices[nb_max] = j;
                nb_max++;
            }
        }
     
        // un gagnant
        if (nb_max == 1)
        {
            printf("arbitre %i egalité %i", info->id_arbitre, vainqueur);
        } else if (nb_max != 1) // cas d'égalité
        {
            printf("arbitre %i egalité ", info->id_arbitre);
            for (int j = 0; j < nb_max; j++)
            {
                printf ("%i", indices[j]);
     
                //pthread_create(&threads[indices[j]], 
                //NULL, joueur, &info);
            }
            printf ("\n");
        }
     
        // attente des joueurs pour un nouveau tirage
        pthread_barrier_wait(&barriere_decision); 
     
        pthread_exit(NULL);
    }

  5. #5
    Membre du Club
    Femme Profil pro
    Étudiant
    Inscrit en
    Mars 2023
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 23
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2023
    Messages : 9
    Par défaut
    Je dois y aller.

    Je reviendrai demain pour prendre connaissances des futures réponses.

Discussions similaires

  1. Avis sur la bonne utilisation des Threads
    Par Pitivier dans le forum Général Java
    Réponses: 8
    Dernier message: 28/11/2006, 20h07
  2. connexion socket utilisant des threads
    Par alceste dans le forum C++
    Réponses: 16
    Dernier message: 14/10/2006, 12h00
  3. [Débutant]Utilisation des Threads
    Par maniolo dans le forum Débuter avec Java
    Réponses: 19
    Dernier message: 10/07/2006, 11h31
  4. Utilisation des threads
    Par Valinor dans le forum Linux
    Réponses: 2
    Dernier message: 30/11/2005, 16h41
  5. Utilisations des Threads
    Par phoenix440 dans le forum Réseau
    Réponses: 15
    Dernier message: 21/08/2005, 17h19

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