D'accord donc je vais reprendre ce que j'avais commencer à faire en tout premier, qui ressemblait vaguement à ce que zooro a fait, en modifiant quelques trucs.
Merci pour tout.
D'accord donc je vais reprendre ce que j'avais commencer à faire en tout premier, qui ressemblait vaguement à ce que zooro a fait, en modifiant quelques trucs.
Merci pour tout.
Tiens, en cherchant un peu dans un vieux projet de licence sur les signaux, j'ai retrouvé un gestionnaire qui pourrait t'être utile :Envoyé par nanoute
La fonction getSignalCodeName() indique pourquoi le signal a été reçu (tu peux normalement retrouver ces infos dans les pages man, il me semble). Ca peut être utile, en particulier pour le SIGCHLD que le père reçoit quand l'un de ses fils meurt.
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 /* Renvoie un message decrivant la raison pour laquelle le signal a ete recu (en fonction du signal et du code passes en parametre) */ char* getSignalCodeName(int sig, int code) { switch (code) { case SI_USER: return ("kill, sigsend ou raise"); break; case SI_KERNEL: return ("Noyau"); break; case SI_QUEUE: return ("sigqueue"); break; case SI_TIMER: return ("Fin d'un time"); break; case SI_MESGQ: return ("Changement d'état mesq"); break; case SI_ASYNCIO: return ("Fin d'une AIO"); break; } if (sig==SIGCHLD) switch (code) { case CLD_EXITED : return ("fils terminé normalement"); break; case CLD_KILLED : return ("fils tué par un signal"); break; case CLD_DUMPED : return ("fils terminé anormalement"); break; case CLD_TRAPPED : return ("fils en cours de suivi"); break; case CLD_STOPPED : return ("fils arrêté"); break; case CLD_CONTINUED: return ("fils arrêté a redémarré"); break; } return "raison inconnue"; } void gere_signal(int sig, siginfo_t *infos, void *n) { char sig_infos[256]; memset(sig_infos, '\0', 256); snprintf(sig_infos, 255, "Raison:%d (%s)", infos->si_code, getSignalCodeName(sig, infos->si_code)); switch (signum) { case SIGINT: case SIGQUIT: case SIGTERM: TRACE("Reception du signal de terminaison %d. %s. Exit.", signum, sig_infos); exit(EXIT_SUCCESS); break; case SIGCHLD: { pid_t fpid = waitpid(-1, NULL, WNOHANG); TRACE("Reception du signal SIGCHLD pour le processus %d. %s.", fpid, sig_infos); } break; default: TRACE("Reception du signal %d inattendue. %s. Aucun traitement particulier.", signum, sig_infos); break; } } int main(void) { struct sigaction sSigAction; static sigset_t sSigMask; /* Gestionnaire de signaux */ sigemptyset(&sSigMask); sigprocmask(SIG_SETMASK, &sSigMask, NULL); sSigAction.sa_handler = gere_signal; sigaction(SIGINT, &sSigAction, NULL); sigaction(SIGQUIT, &sSigAction, NULL); sigaction(SIGTERM, &sSigAction, NULL); sigaction(SIGCHLD, &sSigAction, NULL); /* creation des fils */ creer_boulanger(); creer_patissier(); creer_clients(30); /* boucle infinie */ while (1) { sleep(1); } return EXIT_SUCCESS; }
Je n'ai pas pu compiler chez moi (sous Windows), mais je crois que le fichier d'entête signal.h suffit pour gérer les signaux (pas trop sûr de moi sur ce coup-là ).
Fais aussi attention à ne pas créer de processus zombie en demandant quand le processus ne fait plus rien, sinon ça devient embarassant.
signal.h doit être inclue, et il faut le consulter pour savoir quels signaux utiliser selon son sytème.Envoyé par zooro
Il faudra peut-être aussi <sys/wait.h> pour waitpid().Envoyé par Shugo78
Pour le moment j'ai commencé à lier mes processus avec des messages par file IPC (comme demandé). Mais je ne suis pas sûre que cela puisse bien s'utiliser comme çà.
Il reste encore pas mal de choses à faire.
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 #include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <unistd.h> #define max 20 #define min 30 /* deux macros pour les traces (plusieurs processus, le PID peut etre utile dans les traces) */ #define ERREUR(msg,...) do { \ fprintf(stderr, "Processus %d, fonction %s: ERREUR: " msg "\n", getpid(), __FUNCTION__, ##__VA_ARGS__); \ } while(0) #define TRACE(msg,...) do { \ printf("Processus %d, fonction %s: " msg "\n", getpid(), __FUNCTION__, ##__VA_ARGS__); \ } while(0) /* travail du boulanger */ void boulanger(void) { int p1,p2; int idfile_A1_B = msgget(CLE_FILE, 0666| IPC_CREAT); mon_message m_A1; int stock_A1; //Reçoit le stock de A1 pour savoir jusqu'à combien de pains il peut envoyer (dans la limite de 20 par jour) if(msgrcv(idfile_A1_B, (void*)&m_A1, TAILLE_MESSAGE, 0, 0);) { while(stock<=max) { p1=fabrique(); p2=fabrique(); stock=p1+p2; } } //Fournit A1 en P1 et en P2 jusqu'à ce que le stock de A1 soit égal à 100 while(stock_A1<=100) { envoi_stock(p1); envoi_stock(p2); envoi_msg(A2); } } /* cree le fils qui va jouer le role du boulanger */ void creer_boulanger(void) { pid_t pid = fork(); switch (pid) { case -1: /* Erreur */ ERREUR("Erreur lors du fork. Exit."); exit(EXIT_FAILURE); break; case 0: /* Processus fils */ boulanger(); break; default: /* Processus père */ TRACE("Fils créé avec le PID %d", pid); break; } } /* travail du premier apprenti */ void A1(void) { int idfile_A1_B = msgget(CLE_FILE, 0666| IPC_CREAT); mon_message m_A1; //mise à jour des stocks P1 et P2 //A1 fournit A2 en pain selon stocks //mise à jour des stocks P1 et P2 /*demande à B de fournir des pains car les stocks en P1 ou/et en P2 sont égaux ou inférieur au minimum fixé*/ if((a1<=min)||(a2<=min)) { if (idfile_A1_B == -1) { perror("Erreur sur la file"); exit(ERR_MSG); } m_A1.type_message = 1; m_A1.donnees=1; msgsnd(idfile_A1_B,(void*)&m_A1, TAILLE_MESSAGE,0); } } /* travail du deuxieme apprentis */ void A2(void) { int idfile_client_A2 = msgget(CLE_FILE, 0666| IPC_CREAT); mon_message m_client; mon_message m_A2; if (idfile_client_A2 == -1) { perror("Erreur sur la file"); exit(ERR_MSG); } //reçoit la commande des 30 Clients //reçoit les pains par A1 //envoi commande au client m_A2.type_message = 1; if(m_client.donnees=1) { m_A2.donnees=1; msgsnd(idfile_client_A2,(void*)&m_A2, TAILLE_MESSAGE,0); printf("Envoi de la commande"); } } /* cree les fils qui vont jouer le role des apprentis du patissier */ void creer_patissier(void) { pid_t pid; /* Créer A1 */ pid = fork(); switch (pid) { case -1: /* Erreur */ ERREUR("Erreur lors du fork pour A1. Exit."); exit(EXIT_FAILURE); break; case 0: /* Processus fils */ A1(); break; default: /* Processus père */ TRACE("Fils A1 créé avec le PID %d", pid); break; } /* Créer A2 */ pid = fork(); switch (pid) { case -1: /* Erreur */ ERREUR("Erreur lors du fork pour A2. Exit."); exit(EXIT_FAILURE); break; case 0: /* Processus fils */ A2(); break; default: /* Processus père */ TRACE("Fils A2 créé avec le PID %d", pid); break; } } /* travail d'un client */ void client(int i) { int idfile_client_A2 = msgget(CLE_FILE, 0666| IPC_CREAT); mon_message m_client; mon_message m_A2; int commande; commande=rand()/RAND_MAX; //0 ou 1 pain commandé //envoi commande de client i à A2 if (idfile_client_A2 == -1) { perror("Erreur sur la file"); exit(ERR_MSG); } m_client.type_message = 1; m_client.donnees=commande; msgsnd(idfile_client_A2,(void*)&m_client, TAILLE_MESSAGE,0); printf("Commande passée :%s",commande,"pain(s)"); //reçoit le pain msgrcv(idfile_client_A2, (void*)&m_A2, TAILLE_MESSAGE, 0, 0); if(m_A2.donnees=2) { printf("Pain reçu"); } } /* cree les fils qui joueront le role des nb clients */ void creer_clients(int nb) { int i = 0; pid_t pid = 0; for(i=0; i<nb; i++) { pid = fork(); switch (pid) { case -1: /* Erreur */ ERREUR("Erreur lors du fork pour le client %d. Exit.", i); exit(EXIT_FAILURE); break; case 0: /* Processus fils */ client(i); break; default: /* Processus père */ TRACE("Fils %d créé avec le PID %d", i+1, pid); break; } } } /* point d'entree */ int main(void) { creer_boulanger(); creer_patissier(); creer_clients(30); while (1) { sleep(1); } return EXIT_SUCCESS; }
Oui c'est vrai j'avais oublièEnvoyé par zooro
Tu devrais tester la valeur de retour de msgget(-1 en cas d'erreur) et ensuite tu envoie l'erreur(qui est stocké dans la chaine errno )
Pourquoi utiliser sleep() ?
Si j'étais à ta place, je décomposerais encore les fonctions boulanger(), A1(), A2() et client() en sous-fonctions.
Par exemple, que doit faire le boulanger B ?
L'énoncé dit
Donc, le boulanger doit faire la succession d'actions suivantes, en boucle:Un boulanger B fabrique deux sortes de pains, le P1 et le P2.
Il est ne produit pas plus de 20 pains par jour.
Il fournit un pâtissier qui peut stocker jusqu’à 100 pain.
Le pâtissier emploie de deux apprentis : A1, qui reçoit les pains, et A2, qui les vends aux clients.
A1 envoie des commandes à B pour lui demander de produire des pain quand les stocks de P1 ou P2 sont bas.
- recevoir la commande de A1,
- fabriquer le nombre de pains demandés dans la commande,
- envoyer les pains fabriqués à A1.
Et voilà, la fonction boulanger() est écrite !
Il reste trois sous-problèmes à régler, mais c'est plus simple: lire un message dans une boîte de messages IPC ("recevoir la commande"), décoder un message reçu de A1 ("fabriquer le nombre de pains demandés"), et envoyer un message dans une boîte de messages IPC ("envoyer les pains").
tu as déjà bien avancer , je crois que tu as fais le plus gros.
Voilà, donc pour le moment j'ai ça :
Sauf que j'ai un peu de mal à voir ce que doit faire fabriquer_pain ?!
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 void boulanger(void) { recevoir_commande(); fabriquer_pain(); envoyer_commande(); } void recevoir_commande(mon_message m,int idfile) { idfile = msgget(CLE_FILE, 0666| IPC_CREAT); if (idfile == -1){ perror("Erreur sur la file"); exit(ERR_MSG); } msgrcv(idfile,(void*)&m, TAILLE_MESSAGE,0); } void fabriquer_pain(nb_pain) { } void envoyer_commande() { idfile = msgget(CLE_FILE, 0666| IPC_CREAT); if (idfile == -1){ perror("Erreur sur la file"); exit(ERR_MSG); } msgsnd(idfile,(void*)&m, TAILLE_MESSAGE,0); }
C'est vrai qu'en l'occurrence, il ne sert pas à grand chose.Envoyé par nanoute
Pour la fonction boulanger(), je voyais plutôt quelque chose comme ça:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 void boulanger(void) { int nb_p1 = 0; /* nombre de pains de type P1 à fabriquer */ int nb_p2 = 0; /* nombre de pains de type P2 à fabriquer */ while (1) { recevoir_commande(&p1, &p2); envoyer_commande(p1, p2); } }
Pour mes fonctions recevoir et envoyer je laisse ce que j'ai fait alors?
C'est pas mal. On peut étoffer un peu, et décomposer encore les fonctions. Mais pour un début, c'est bien.Envoyé par nanoute
Edit: En faisant un petit test, je me suis rendu compte que je n'avais pas suivi mon propre conseil
Dans les fonctions creer_*, il faut ajouter un exit(EXIT_SUCCESS) après l'appel à boulanger(), client(), A1() et A2(). Sinon le code est faux et des processus indésirables sont créés...
C'est en effet pas mal pour un début et ensuite ?
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager