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 :

Programmation système (signaux, tube)


Sujet :

C

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

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2023
    Messages : 9
    Points : 2
    Points
    2
    Par défaut Programmation système (signaux, tube)
    Bonjour,

    Je bloque sur la création d'une fonction. L'objectif est de créer une fonction qui va lire des nombres sur le descripteur tube et les comparer à val. Ces nombres sont envoyés par des processus fils. Si le nombre lu est supérieur (respectivement inférieur) à val alors le signal SIGUSR1 (respectivement SIGUSR2) est envoyé au processus fils qui a écrit cette valeur. Sinon (les deux valeurs sont égales), c’est le signal SIGTERM qui est envoyé au processus fils correspondant et les valeurs suivantes lues sur tube provoqueront systématiquement l’envoi du signal SIGTERM aux processus à l’origine de ces valeurs. La fonction retourne le pid du vainqueur lorsqu’il n’y a plus rien à lire sur tube.

    J'ai commencé à écrire mais je bloque sur la façon d'envoyer les signaux au bon processus fils (grâce à son pid). De plus, j'ai un doute sur la lecture dans le tube.

    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
     
    pid_t lecture(int val, int tube)
    {
        int valeur_lue;
        int pid_gagnant;
     
        // Bloque les signaux SIGUSR1, SIGUSR2 et SIGTERM pendant la lecture dans le tube
        sigset_t masque;
        sigemptyset(&masque);
        sigaddset(&masque, SIGUSR1);
        sigaddset(&masque, SIGUSR2);
        sigaddset(&masque, SIGTERM);
        sigprocmask(SIG_BLOCK, &masque, NULL); 
     
        // Pb : lire les valeurs dans le tube et connaître le pid du fils qui écrit 
        // chaque valeur
        while (read(tube, &valeur_lue, sizeof(int) > 1))
        {
            // On compare 
            if (valeur_lue > val)
            {
                // Ici, comment trouver le bon pid ?
                kill (pid_du_fils_qui_a_ecrit, SIGUSR1);
            } else if (valeur_lue < val)
            {
                kill (pid_du_fils_qui_a_ecrit, SIGUSR2);
            } else 
            {
                kill (pid_du_fils_qui_a_ecrit, SIGTERM);
            }
        }
     
        sigprocmask(SIG_UNBLOCK, &masque, NULL); // Débloque les signaux SIGUSR1, SIGUSR2 et SIGTERM
     
     
        return pid_gagnant;
    }
    Merci d'avance

  2. #2
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    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 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Ton code laisse des zones d'ombre. Par exemple la fonction reçoit un int tube en paramètre. A-t-elle bien reçu le côté [0] du tube (celui qui sert à lire)? Et les différents processus (père/fils) ont-ils bien fermé de leurs côtés la partie du tube qui ne leur sert pas?

    Ensuite si la fonction doit envoyer une info (un signal) au pid qui lui écrit, alors elle doit connaitre ce pid donc à minima le recevoir en paramètre (tu n'as quand-même pas cédé à la tentation de mettre ce pid en globales j'espère !!!). Ou alors le fils peut envoyer 2 int dans le tube
    • son pid
    • la valeur

    Ainsi le lecteur du tube saura qui lui écrit.
    Pour le reste ta lecture me semble correcte, et tes kill aussi.
    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]

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

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2023
    Messages : 9
    Points : 2
    Points
    2
    Par défaut
    Alors, voici mon main avec la création des processus fils (il peut y avoir des erreurs sur la gestion du tube et la création des processus)
    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
     
    int main(int argc, char *argv[]) 
    {
     
        if (argc != 3) 
        {
            raler ("usage: ./devinette <nb_secret> <nb_de_processus>");
            exit (1);
        }
     
        int nb_secret = atoi (argv[1]);
        int nb_de_processus = atoi (argv[2]);
     
        // On prépare avant le fork
        preparer ();
     
        int tube[2];
        if (pipe(tube) == -1) 
        {
            raler ("Erreur création tube");
        }   
     
        pid_t pid;
        int i;
        for (i = 0; i < nb_de_processus; i++) {
            switch (pid = fork())
            {
                case -1:
                    raler ("Fork");
                case 0:
                    //Fils
                    close (tube[0]);
                    fils (tube[1]);
                    close (tube[1]);
                default:
                    break;
            }
        }
        // Père
        close (tube[1]); 
        int vainqueur = lecture (nb_secret, tube[0]); 
        close (tube[0]);
        printf("Le fils avec PID %d a trouvé le nombre secret\n", vainqueur);
     
        attendre_fils (nb_de_processus);
     
        return 0;
    }
    Ensuite, comme c'est un sujet de TP et pas projet perso, les fonctions à écrire étaient données avec les entêtes et dans cette fonction je ne peux pas passer le pid en paramètre.
    De même, ce n'est pas clairement indiqué, mais il est seulement écrit qu'on écrira les nombres dans le tube Je me demande si justement on peut le faire autrement,
    Si ce n'est pas possible, est-ce que pour la méthode d'écrire le pid dans le tube, il suffit d'utiliser ce que renvoie fork modifier l'écriture dans le tube (et la lecture) en ajoutant un entier pid ?

    Et non ce n'est pas une variable globale, mais j'avais donné un nom de variable qui n'existe pas juste pour montrer la forme.

  4. #4
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    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 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par lylooIII Voir le message
    (il peut y avoir des erreurs sur la gestion du tube et la création des processus)
    Exact gros souci. Vu que le fils ne meurt pas en fin de job, il repart dans sa propre copie de la boucle et va lui-même générer n fils (qui eux aussi vont générer n fils etc). T'as écrit une fork-bomb.
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    for (i = 0; i < nb_de_processus; i++) {
    	switch (pid=fork()) {
    		case -1:
    			raler ("Fork");
    			break;
    		case 0:
    			//Fils
    			close (tube[0]);
    			fils(tube[1]);
    			close(tube[1]);
    			exit(0);	// Pour éviter au fils de repartir dans la boucle...
    	}
    }

    Citation Envoyé par lylooIII Voir le message
    Ensuite, comme c'est un sujet de TP et pas projet perso, les fonctions à écrire étaient données avec les entêtes et dans cette fonction je ne peux pas passer le pid en paramètre.
    A la réflexion c'est en réalité inutile. Il y a indépendance des processus. C'est donc probablement pour ça que la fonction n'a pas été prévue pour recevoir un pid, elle ne peut pas le recevoir (le fils ne pouvant pas appeler la fonction du père).

    Citation Envoyé par lylooIII Voir le message
    De même, ce n'est pas clairement indiqué, mais il est seulement écrit qu'on écrira les nombres dans le tube Je me demande si justement on peut le faire autrement,
    Tu as un prof, tu peux le lui demander.
    De mon point de vue, je ne vois que 3 méthodes (qui se ressemblent dans les grandes lignes)
    • tu envoies une string (style "123:444" signifiant "pid=123, val=444). Le lecteur recevant la string pourra l'exploiter et extraire "123" et "444"
    • tu envoies 2 int à suivre (123 puis 444). Le lecteur devra faire 2 lectures à suivre
    • tu regroupes "pid" et "valeur" dans une structure et tu envoies la structure que le lecteur récupèrera à l'identique


    Citation Envoyé par lylooIII Voir le message
    Si ce n'est pas possible, est-ce que pour la méthode d'écrire le pid dans le tube, il suffit d'utiliser ce que renvoie fork modifier l'écriture dans le tube (et la lecture) en ajoutant un entier pid ?
    Tu ne peux pas utiliser fork() car quand tu es dans le fils, fork() vaut 0. Faut passer par getpid(). Le fils récupère son pid qu'il stocke dans une variable. A la réflexion tu ne peux pas non plus disjoindre "pid" et "valeur" car s'il y a deux écritures dans le tube, rien ne garantit que "pid" et "valeur" seront accolées (on peut très bien avoir "fils1 écrit pid1" puis "fils2 écrit pid2" puis "fils1 écrit valeur1" et le père est perdu.
    Donc faut trouver un moyen de regrouper "pid" et "valeur" et envoyer le tout en une fois. Ou alors j'ai rien pigé à l'énoncé...
    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]

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

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2023
    Messages : 9
    Points : 2
    Points
    2
    Par défaut
    Merci pour les idées, je vais tenter d'envoyer le pid du fils et la valeur qui l'envoie en même temps. Et oui j'ai été trop rapide en pensant à utiliser fork pour récupérer le pid.
    J'oublie toujours la sécurité exit (0) dans le fils ...

    Par contre j'ai une question plus globale sur la gestion des signaux par rapport à cet exercice. J'ai compris que lorsqu'on définissait l'action/fonction associée à un signal, il fallait limiter au max la durée de cette fonction associée. Donc dans les exos on utilisait souvent une variable globale "volatile sig_atomic_t signal_recu" (par exemple) qu'on modifiait dans la fonction et qu'on testait dans le programme principal.

    Mais ici, plusieurs signaux différents peuvent arriver en "même temps", puisque le père envoie des signaux à chaque fils, et modifier cette variable avant qu'elle ait été testée dans le programme.
    En fait, je me demande juste comment bien définir les fonctions associées aux signaux et comment bien traiter la reçue des signaux. Peut-être en masquant les signaux le temps de traiter la variable globale ?

  6. #6
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    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 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par lylooIII Voir le message
    Mais ici, plusieurs signaux différents peuvent arriver en "même temps", puisque le père envoie des signaux à chaque fils,
    Cette règle de temps de la fonction associée ne vaut que pour un process qui reçoit 50 signal par secondes. Ici ce ne sera pas le cas car chaque signal que le père enverra dépendra de la valeur qu'il a lue dans le tube, valeur envoyée par le fils. C'est donc en réalité le fils qui gère la fréquence du signal qu'il reçoit. En plus, le pipe étant bloquant, s'il n'a pas été lu par le père au tour précédent, le fils ne pourra pas y écrire au tour suivant. Tu ne risques vraiment pas le surmenage...
    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]

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

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2023
    Messages : 9
    Points : 2
    Points
    2
    Par défaut
    Merci. Avec cela, j'ai décidé de la même idée d'une variable globale et j'ai fini d'écrire le programme.

    Mais il ne fonctionne pas je l'attends et je n'arrive pas à comprendre (peut-être évident ?) mais lorsque je le fais tourner : le 1er processus fils cherche le nombre et le trouve (fonctionnement attendu, donc si je mets un unique processus tout se passe bien), puis le 2ème processus fils cherche et trouve, et ainsi de suite, au lieu de travailler de façon "parallèle" et arrêter le programme dès que le plus rapide à trouver le nombre secret. C'est un fonctionnement des processus que je n'arrive pas à comprendre.

    Je mets tout le code. Merci d'avance si vous prenez le temps de répondre.

    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
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
     
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <sys/wait.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <time.h>
    #include <signal.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    #include <dirent.h>
     
    #define MIN_VALUE 1
    #define MAX_VALUE 99
    #define TAILLE_CHAINE 256
     
     
    volatile sig_atomic_t signal_recu = 0;
     
     
    void raler (const char *msg) 
    {
        perror (msg);
        exit (1);
    }
     
     
    int getrandint (int a, int b) 
    {
        srand(time(NULL)); // Initialisation du générateur de nombres aléatoires
        return rand() % (b - a + 1) + a; // Retourne un entier aléatoire compris entre a et b inclus
    }
     
    void handler_usr (int signum) 
    {
        if (signum == SIGUSR1) 
        {
            signal_recu = 1;
        } else if (signum == SIGUSR2) 
        {
            signal_recu = 2;
        }
    }
     
    void handler_fin (int signum) 
    {
        (void) signum;
        signal_recu = 3;
        // Ajoutez ici les actions à exécuter à la réception de SIGTERM
    }
     
    void preparer(void) {
        struct sigaction sa_usr, sa_fin;
     
        // Préparation des actions pour les signaux SIGUSR1 et SIGUSR2
        sa_usr.sa_handler = handler_usr;
        sigemptyset(&sa_usr.sa_mask);
        sa_usr.sa_flags = 0;
        sigaction(SIGUSR1, &sa_usr, NULL);
        sigaction(SIGUSR2, &sa_usr, NULL);
     
        // Préparation de l'action pour le signal SIGTERM
        sa_fin.sa_handler = handler_fin;
        sigemptyset(&sa_fin.sa_mask);
        sa_fin.sa_flags = 0;
        sigaction(SIGTERM, &sa_fin, NULL);
    }
     
     
    void fils (int tube)
    {
        // Envoi 1ère proposition
        int proposition = getrandint (MIN_VALUE, MAX_VALUE);
     
        pid_t pid_fils = getpid ();
     
        // Création de la chaîne de caractères à envoyer
        char message[TAILLE_CHAINE];
        snprintf(message, sizeof(message), "%d:%d", pid_fils, proposition); 
     
        if (write(tube, message, strlen(message)+1) < 0) 
        {
            raler("Erreur écriture 1ère proposition dans tube");
        }
     
        printf ("Message 1 : %s\n", message);
     
        sigset_t new, old, vide;
     
        while(1) 
        {
            sigemptyset (&new);
            sigaddset (&new, SIGUSR1);
            sigaddset (&new, SIGUSR2);
            sigaddset (&new, SIGTERM);
            sigprocmask (SIG_BLOCK, &new, &old);
     
            printf ("Valeur de signal recu 1 %i\n", signal_recu);
     
            if (! signal_recu)
            {
                sigemptyset (&vide);
                sigsuspend (&vide); // Attente de la réception d'un signal
            }
     
            sigprocmask (SIG_SETMASK, &old, NULL);
     
            printf ("Valeur de signal recu 2 %i\n", signal_recu);
     
            // Vérification du signal reçu
            if (signal_recu == 1) 
            {
                proposition -= 1; // Décrémentation de la proposition
            } else if (signal_recu == 2) 
            {
                proposition += 1; // Incrémentation de la proposition
            } else if (signal_recu == 3) 
            {
                // Terminaison de la fonction en cas de réception de SIGTERM
                printf("Terminaison du processus fils\n");
                return;
            }
     
            // Envoi de la nouvelle proposition sur le tube
            snprintf(message, sizeof(message), "%d:%d", pid_fils, proposition); 
     
            printf ("Message dans boucle : %s\n", message);
     
            if (write(tube, message, TAILLE_CHAINE) < 0)
            {
                raler ("Erreur écriture nouvelle proposition dans tube");
            }
     
        }
    }
     
     
     
    pid_t lecture(int val, int tube)
    {
        int valeur_lue;
        pid_t pid_du_fils_qui_a_ecrit;
        char chaine_lue[TAILLE_CHAINE]; 
     
        // Bloque les signaux SIGUSR1, SIGUSR2 et SIGTERM pendant la lecture dans le tube
        sigset_t masque;
        sigemptyset(&masque);
        sigaddset(&masque, SIGUSR1);
        sigaddset(&masque, SIGUSR2);
        sigaddset(&masque, SIGTERM);
        sigprocmask(SIG_BLOCK, &masque, NULL); 
     
        // Pb : lire les valeurs dans le tube et connaître le pid du fils qui écrit 
        // chaque valeur
        while (read(tube, chaine_lue, TAILLE_CHAINE) > 0)
        {
            // Extraction du pid et de la proposition depuis la chaîne lue
            pid_du_fils_qui_a_ecrit = atoi(strtok(chaine_lue, ":"));
            valeur_lue = atoi(strtok(NULL, ":"));
     
            printf ("Pid = %i\n", pid_du_fils_qui_a_ecrit);
            printf ("Valeur = %i\n", valeur_lue);
     
            // On compare 
            if (valeur_lue > val)
            {
                // Ici, comment trouver le bon pid ?
                kill (pid_du_fils_qui_a_ecrit, SIGUSR1);
            } else if (valeur_lue < val)
            {
                kill (pid_du_fils_qui_a_ecrit, SIGUSR2);
            } else 
            {
                kill (pid_du_fils_qui_a_ecrit, SIGTERM);
                kill (0, SIGTERM);
                return pid_du_fils_qui_a_ecrit;
            }
        }
     
        sigprocmask(SIG_UNBLOCK, &masque, NULL); // Débloque les signaux SIGUSR1, SIGUSR2 et SIGTERM
     
        return pid_du_fils_qui_a_ecrit;
    }
     
    void attendre_fils (int n)
    {
        // On attend n fois (nb de processus fils) que le processus se termine
        for (int i = 0; i < n; i++)
        {
            int raison;
     
            if (wait (&raison) == -1)
                raler ("wait");
     
            if (WIFEXITED (raison))
            {
                printf ("code de retour du fils %d\n", WEXITSTATUS (raison));
            } else 
            {
                raler ("Erreur exit");
            }
        }
    }
     
    int main(int argc, char *argv[]) 
    {
     
        if (argc != 3) 
        {
            raler ("usage: ./devinette <nb_secret> <nb_de_processus>");
        }
     
        int nb_secret = atoi (argv[1]);
        int nb_de_processus = atoi (argv[2]);
     
        // On prépare avant le fork
        preparer ();
     
     
        int tube[2];
        if (pipe(tube) == -1) 
        {
            raler ("Erreur création tube");
        }   
     
        pid_t pid;
        int i;
        for (i = 0; i < nb_de_processus; i++) {
            switch (pid = fork())
            {
                case -1:
                    raler ("Fork");
                    break;
                case 0:
                    printf ("%i fils\n", i);
                    //Fils
                    close (tube[0]);
                    fils (tube[1]);
                    close (tube[1]);
                    exit (0);
                default:
                    break;
            }
        }
     
        close (tube[1]); 
        int vainqueur = lecture (nb_secret, tube[0]); 
        close (tube[0]);
        printf("Le fils avec PID %d a trouvé le nombre secret\n", vainqueur);
     
        attendre_fils (nb_de_processus);
     
        return 0;
    }

  8. #8
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    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 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Alors dans ton code
    • la fonction lecture() ne doit pas retourner de valeur dans la boucle (ou alors tout ce qui est écrit après n'est pas traité)
    • je ne vois pas pourquoi tu fais une première écriture distincte des autres (plus c'est complexifié, moins ça marche)
    • tu ne dois pas initialiser le random à chaque appel de l'aléatoire (sinon ce n'est pas une "initialisation")
    • tu aurais pu passer par la structure ce qui simplifie l'encodage/décodage
    • autant éviter de préparer si la création du tube échoue
    • tu as déjà 3 valeurs magiques "SIGUSR1", "SIGUSR2" et "SIGTERM". Pourquoi en créer 3 autres "1, 2 et 3" qui obfusquent un peu plus le bouzin???
    • tu ne dois jamais jamais jamais utiliser sizeof() pour un tableau (le jour où il devient pointeur c'est le bug). Tu as un tableau, tu connais forcément sa taille donc tu utilises sa taille (en plus ici c'est une macro donc c'est fait pour)
    • reprendre un autre code pour ne pas partir de zéro c'est pas interdit, mais faut quand-même nettoyer les include inutiles


    PS: si le fils meurt par kill(), alors ce n'est pas une erreur => il ne faut pas appeler "raler()" quand WIFEXITED() est faux mais afficher le signal ayant causé la mort.

    Voici mon propre code.
    Code c : 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
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    #include <sys/wait.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <time.h>
    #include <signal.h>
    #include <stdlib.h>
    #include <errno.h>
     
    #define MIN_VALUE 1
    #define MAX_VALUE 99
     
    typedef struct {
    	pid_t pid;
    	int val;
    } t_info;
     
    volatile sig_atomic_t signal_recu=0;
     
    void raler(const char* const msg) {
    	perror(msg);
    	exit(1);
    }
     
    int getrandint(int a, int b) {
    	// Retourne un entier uniformément aléatoire compris entre a et b inclus
    	return rand() / RAND_MAX * (b - a + 1) + a;
    }
     
    void handler_usr(int signum) {
    	extern volatile sig_atomic_t signal_recu;
    	switch (signum) {
    		case SIGUSR1:
    		case SIGUSR2:
    			signal_recu=signum;
    			break;
    		default:
    			raler("signal reçu incorrect !!!");
    	}
    }
     
    void handler_fin(int signum) {
    	extern volatile sig_atomic_t signal_recu;
    	signal_recu=SIGTERM;
    	// Ajoutez ici les actions à exécuter à la réception de SIGTERM
    }
     
    void preparer(void) {
    	struct sigaction sa_usr, sa_fin;
     
    	// Préparation des actions pour les signaux SIGUSR1 et SIGUSR2
    	sa_usr.sa_handler=handler_usr;
    	sigemptyset(&sa_usr.sa_mask);
    	sa_usr.sa_flags=0;
    	sigaction(SIGUSR1, &sa_usr, NULL);
    	sigaction(SIGUSR2, &sa_usr, NULL);
     
    	// Préparation de l'action pour le signal SIGTERM
    	sa_fin.sa_handler=handler_fin;
    	sigemptyset(&sa_fin.sa_mask);
    	sa_fin.sa_flags=0;
    	sigaction(SIGTERM, &sa_fin, NULL);
    }
     
    void fils(int tube) {
    	extern volatile sig_atomic_t signal_recu;
    	t_info info;
     
    	// Initialisation 1ère proposition
    	info.pid=getpid();
    	info.val=getrandint(MIN_VALUE, MAX_VALUE);
     
    	sigset_t new, old, vide;
    	while (1) {
    		// Envoi proposition sur le tube
    		printf("pid=%u - info dans boucle : %u/%d\n", getpid(), info.pid, info.val);
    		if (write(tube, &info, sizeof(info)) < 0) {
    			raler("Erreur écriture nouvelle proposition dans tube");
    		}
    		sigemptyset(&new);
    		sigaddset(&new, SIGUSR1);
    		sigaddset(&new, SIGUSR2);
    		sigaddset(&new, SIGTERM);
    		sigprocmask(SIG_BLOCK, &new, &old);
     
    		printf("pid=%u - Valeur de signal recu 1 %i\n", getpid(), signal_recu);
     
    		if (signal_recu == 0) {
    			sigemptyset(&vide);
    			sigsuspend(&vide); // Attente de la réception d'un signal
    		}
     
    		sigprocmask(SIG_SETMASK, &old, NULL);
     
    		printf("pid=%u - Valeur de signal recu 2 %i\n", getpid(), signal_recu);
     
    		// Vérification du signal reçu
    		switch (signal_recu) {
    			case SIGUSR1:
    				info.val-=1; // Décrémentation de la proposition
    				break;
    			case SIGUSR2:
    				info.val+=1; // Incrémentation de la proposition
    				break;
    			case SIGTERM:
    				// Terminaison de la fonction en cas de réception de SIGTERM
    				printf("pid=%u - Terminaison du processus fils\n", getpid());
    				return;
    			default:
    				printf("pid=%u - Signal reçu %d inconnu !!!\n", getpid(), signal_recu);
    		}
    	}
    }
     
    pid_t lecture(int val, int tube) {
    	t_info info;
    	// Bloque les signaux SIGUSR1, SIGUSR2 et SIGTERM pendant la lecture dans le tube
    	sigset_t masque;
    	sigemptyset(&masque);
    	sigaddset(&masque, SIGUSR1);
    	sigaddset(&masque, SIGUSR2);
    	sigaddset(&masque, SIGTERM);
    	sigprocmask(SIG_BLOCK, &masque, NULL); 
     
    	// Lecture tube
    	while (read(tube, &info, sizeof(info)) > 0) {
    		// Extraction du pid et de la proposition depuis l'information
    		printf("Pid=%i, valeur=%i\n", info.pid, info.val);
     
    		// On compare 
    		if (info.val > val) {
    			kill(info.pid, SIGUSR1);
    		} else if (info.val < val) {
    			kill(info.pid, SIGUSR2);
    		} else {
    			kill(info.pid, SIGTERM);
    			kill(0, SIGTERM);
    			break;
    		}
    	}
     
    	sigprocmask(SIG_UNBLOCK, &masque, NULL); // Débloque les signaux SIGUSR1, SIGUSR2 et SIGTERM
     
    	return info.pid;
    }
     
    void attendre_fils(size_t n) {
    	// On attend n fois (nb de processus fils) que le processus se termine
    	for (size_t i=0; i < n; i++) {
    		int raison;
    		pid_t pid;
     
    		if ((pid=wait(&raison)) < 0)
    			raler("wait");
     
    		if (WIFEXITED(raison)) {
    			printf("code de retour du fils(%d)=%d\n", pid, WEXITSTATUS(raison));
    		} else {
    			printf("code de kill du fils(%d)=%d\n", pid, WTERMSIG(raison));
    		}
    	}
    }
     
    int main(int argc, char *argv[]) {
    	if (argc != 3) {
    		raler("usage: ./devinette <nb_secret> <nb_de_processus>");
    	}
     
    	int nb_secret=atoi(argv[1]);
    	int nb_de_processus=atoi(argv[2]);
     
    	int tube[2];
    	if (pipe(tube) < 0) {
    		raler("Erreur création tube");
    	}   
     
    	// Initialisation du générateur de nombres aléatoires
    	srand(time(NULL)^getpid());
     
    	// On prépare avant le fork
    	preparer();
     
    	pid_t pid;
    	for (size_t i=0; i < nb_de_processus; i++) {
    		switch (pid=fork())
    		{
    			case -1:
    				raler("Fork");
    				break;
    			case 0:
    				printf("%lu fils\n", i);
    				//Fils
    				close(tube[0]);
    				fils(tube[1]);
    				close(tube[1]);
    				exit(0);
    		}
    	}
     
    	close(tube[1]); 
    	int vainqueur=lecture(nb_secret, tube[0]); 
    	close(tube[0]);
     
    	attendre_fils(nb_de_processus);
    	printf("Le fils avec PID %d a trouvé le nombre secret\n", vainqueur);
     
    	return 0;
    }
    Ce code, dans lequel j'affiche largement les pid, montre bien que les fils tournent en parallèle. Parfois c'est l'un, parfois c'est l'autre.
    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]

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

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2023
    Messages : 9
    Points : 2
    Points
    2
    Par défaut
    Alors là merci beaucoup. Non seulement pour l'aide sur la question en elle-même mais aussi les conseils plus généraux et la réécriture du programme (je ne m'attendais pas à une réponse si complète). J'ai fait certaines erreurs que je ne fais pas normalement car je ne pensais qu'aux signaux, donc merci.

    Je reprendrais à tête reposée votre programme demain et le comparer aux erreurs du mien.

    Bonne nuit !

  10. #10
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    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 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par lylooIII Voir le message
    Alors là merci beaucoup. Non seulement pour l'aide sur la question en elle-même mais aussi les conseils plus généraux et la réécriture du programme (je ne m'attendais pas à une réponse si complète).
    C'est normal, si on est là c'est pour aider.
    Ici il y a ceux qui viennent demander du code tout fait pour éviter de bosser et retourner voir leurs conneries sur tiktok, et ceux qui viennent pour avoir vraiment de l'aide car ils veulent progresser.
    Dans ton cas c'est clairement la seconde option. Donc de là il devient tout aussi clair que te filer un code te sera cent fois plus profitable que de te guider par des dizaines de posts peut-être parfois flous ou mal compris. On gagne du temps tous les deux car je sais que ce code tu ne feras pas que le prendre mais que tu l'étudieras

    PS: je l'ai un peu corrigé ce matin donc si tu l'as pris hier soir cette version est meilleure.
    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]

Discussions similaires

  1. Réponses: 1
    Dernier message: 23/10/2014, 08h20
  2. Réponses: 4
    Dernier message: 18/06/2014, 14h57
  3. Réponses: 4
    Dernier message: 28/11/2013, 20h40
  4. Programmation Système : Signaux
    Par fred44ooo dans le forum Linux
    Réponses: 7
    Dernier message: 04/05/2010, 09h13
  5. [Programmation système] Programme de base
    Par tooney dans le forum C
    Réponses: 7
    Dernier message: 11/07/2005, 21h36

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