View Full Version : [C linux] Chiarimenti sulla wait()
VegetaSSJ5
17-09-2004, 15:56
Salve a tutti, ho bisogno di un chiarimento sulla funzione wait(). Da quello che ho capito un processo fa la fork e vuole aspettare la terminazione del figlio. Quando il figlio termina la propria esecuzione manda un SIGCHLD al padre. Se il padre fa una wait(NULL), riprende l'esecuzione qando il figlio ha terminato, giusto? Ho fatto un programmino che usa questa wait(), in patica il padre crea N figli e vuole riprendere a funzionare quando tutti i figli hanno terminato. Ho scritto questo pezzettino:for (i=0; i<N; ++i) {
pid_t pid=fork();
if (pid==0) spesa();
}
while (j<N) {
if ((i=(int)wait(NULL)) <=0) {
perror("Errore nella wait");
exit(-1);
}
printf("Il cliente %d ha terminato la sua esecuzione\n", i);
}
printf("\nTutti i clienti hanno terminato la propria esecuzione\n");In fase d'esecuzione il programma termina perchè mi stampa il messaggio di errore della wait dicendo "Errore nella wait: No child processes".
Qualcuno mi sa aiutare??:confused:
ilsensine
17-09-2004, 16:02
La wait si trova sia nel path del padre che dei figli, mi sembra.
VegetaSSJ5
17-09-2004, 16:04
Originariamente inviato da ilsensine
La wait si trova sia nel path del padre che dei figli, mi sembra.
ilsensine chiaramente i codice non è quello , l'ho un po' semplificato io perchè in mezzo alle operazioni ci sono altre cose (semafori, memoria condivisa). il figlio esegue una exit(0) all'interno della funzione spesa().
ilsensine
17-09-2004, 16:11
Per caso tra le semplificazioni hai anche tolto l'inizializzazione e l'incremento di j?
VegetaSSJ5
17-09-2004, 16:23
Originariamente inviato da ilsensine
Per caso tra le semplificazioni hai anche tolto l'inizializzazione e l'incremento di j?
ilsensine ti riporto il codice di tutta la funzionevoid genera_clienti (int N) {
int i, j, numf, tipo, semaforo, bilancia, listaspesa[10];
if ((semaforo= semget(5785, 10, IPC_CREAT | IPC_EXCL)) <0) {
perror("Errore nella creazione del semaforo");
exit(-1);
}
if ((bilancia= semget(3486, 1, IPC_CREAT | IPC_EXCL)) <0) {
perror("Errore nella creazione del semaforo bilancia");
exit(-1);
}
semun ctl_arg;
ctl_arg.array=(unsigned short *) calloc (10, sizeof(unsigned short));
if (semctl(semaforo, 0, SETALL, ctl_arg) <0) {
perror("Errore nella chiamata a semctl -1-");
exit(-1);
}
printf("\nSto generando i clienti...\n\n");
ctl_arg.val=1;
if (semctl(bilancia, 0, SETVAL, ctl_arg) <0) {
perror("Errore nella chiamata a semctl per bilancia");
exit(-1);
}
for (i=0; i<N; i++) {
for (j=0; j<10; j++) listaspesa[j]=0;
numf=rand()%10;
if (numf<3) numf+=3;
for (j=0; j<numf; j++) {
tipo=rand()%10;
while (listaspesa[tipo]!=0) (++tipo)%10;
listaspesa[tipo]=rand()%10;
}
pid_t pid=fork();
if (pid==0) {
casse=(int *) shmat (fdcasse, 0, SHM_RND);
printlistaspesa(listaspesa);
spesa(listaspesa, semaforo, bilancia);
}
else sleep(1);
}
j=0;
ctl_arg.array=(unsigned short *) calloc (10, sizeof(unsigned short));
for (i=0; i<10; i++) ctl_arg.array[i]=1;
if (semctl(semaforo, 0, SETALL, ctl_arg) <0) {
perror("Errore nella chiamata a semctl -2-");
exit(-1);
}
while (j<N) {
if ((i=(int)wait(NULL)) <=0) {
perror("Errore nella wait");
exit(-1);
}
printf("Il cliente %d ha terminato la sua esecuzione\n", i);
++j;
}
printf("\nTutti i clienti hanno terminato la propria esecuzione\n");
}
ilsensine
17-09-2004, 16:35
Sembra corretto; non vorrei che qualche figlio va in crash (anche se questo dovrebbe mandare in crash anche il padre, credo).
Puoi allegare il codice completo, così lo compilo & testo qui in locale?
VegetaSSJ5
17-09-2004, 16:41
ecco il programma. ti avverto comunque che il programma ancora non è terminato quindi mancano ancora delle cose importanti (come la deallocazione delle risorse dei semafori, infatti se il programma va in crash devi cambiare le key dei semafori e ricompilare o riavviare il sistema per far ripartire il programma). in pratica il fatto della wait mi serve perchè se non la facessi il padre terminerebbe la propria esecuzione e i figli sarebbero zombie, e questo non lo posso permettere perchè andrebbe contro le specifiche.
VegetaSSJ5
17-09-2004, 16:47
speriamo che il sensine non abbia scoperto che in realtà era un virus! a quest'ora dovrebbe già essergli scoppiato il pc! :fiufiu:
:sofico: :sofico: ;)
ilsensine
17-09-2004, 16:58
Vedo errori un pò ovunque, tranne nel tuo wait. Mi puzza di buffer overflow o altre delizie, credo che faresti bene a controllare i vari passi.
Ad esempio qui
if (semctl(semaforo, 0, SETALL, ctl_arg) <0) {
perror("Errore nella chiamata a semctl -1-");
exit(-1);
}
Mi da un bel "permission denied" alla prima esecuzione, segno che c'è qualcosa che non va.
Sotto root non ho questo errore, il programma va avanti con errori nei punti più impensabili.
ilsensine
17-09-2004, 17:00
nb per evitare di riavviare ogni volta, credo che ti basti togliere IPC_EXCL nelle semget.
VegetaSSJ5
17-09-2004, 17:05
Originariamente inviato da ilsensine
nb per evitare di riavviare ogni volta, credo che ti basti togliere IPC_EXCL nelle semget.
azz! ti ringrazio! :ave:
per il resto hai qualche idea? anche a te ha dato quell'errore a runtime??
ilsensine
17-09-2004, 17:11
Argh!
if ((semaforo= semget(5785, 10, IPC_CREAT >>> | 0600 <<<)) <0) {
perror("Errore nella creazione del semaforo");
exit(-1);
}
if ((bilancia= semget(3486, 1, IPC_CREAT >>> | 0600 <<<)) <0) {
perror("Errore nella creazione del semaforo bilancia");
exit(-1);
}
Nota che anche per il seme del semaforo puoi usare IPC_PRIVATE.
VegetaSSJ5
17-09-2004, 17:19
Originariamente inviato da ilsensine
Argh!
if ((semaforo= semget(5785, 10, IPC_CREAT >>> | 0600 <<<)) <0) {
perror("Errore nella creazione del semaforo");
exit(-1);
}
if ((bilancia= semget(3486, 1, IPC_CREAT >>> | 0600 <<<)) <0) {
perror("Errore nella creazione del semaforo bilancia");
exit(-1);
}
Nota che anche per il seme del semaforo puoi usare IPC_PRIVATE.
intendi la key? quel | 0600 cosa provoca?
ilsensine
17-09-2004, 17:22
Originariamente inviato da VegetaSSJ5
intendi la key? quel | 0600 cosa provoca?
Che puoi USARE il semaforo, ad esempio? :D
VegetaSSJ5
17-09-2004, 17:25
Originariamente inviato da ilsensine
Che puoi USARE il semaforo, ad esempio? :D
dettagli...;)
ilsensine
17-09-2004, 17:29
Se crei il semaforo senza diritti di lettura/scrittura, come fai a modificarlo? ;)
Lo fai già per la shmget, il principio è lo stesso.
Questa patch risolve il problema. Nota che con IPC_PRIVATE, non è necessario specificare IPC_CREAT:
--- main.c.org 2004-09-17 16:48:07.000000000 +0200
+++ main.c 2004-09-17 17:30:52.000000000 +0200
@@ -76,11 +76,11 @@
void genera_clienti (int N) {
int i, j, numf, tipo, semaforo, bilancia, listaspesa[10];
- if ((semaforo= semget(5785, 10, IPC_CREAT | IPC_EXCL)) <0) {
+ if ((semaforo= semget(IPC_PRIVATE, 10, 0600)) <0) {
perror("Errore nella creazione del semaforo");
exit(-1);
}
- if ((bilancia= semget(3486, 1, IPC_CREAT | IPC_EXCL)) <0) {
+ if ((bilancia= semget(IPC_PRIVATE, 1, 0600)) <0) {
perror("Errore nella creazione del semaforo bilancia");
exit(-1);
}
VegetaSSJ5
17-09-2004, 17:36
grazie ilsensine! :ave: :ave:
Originariamente inviato da VegetaSSJ5
per il resto hai qualche idea? anche a te ha dato quell'errore a runtime??
ilsensine
17-09-2004, 17:40
grazie ilsensine! :ave: :ave:
Originariamente inviato da VegetaSSJ5
per il resto hai qualche idea? anche a te ha dato quell'errore a runtime??
Con la patch non ti funziona? A me non capita quell'errore.
VegetaSSJ5
17-09-2004, 17:52
in pratica mi dà l'errore su quella wait quando termina un processo figlio...
ilsensine
17-09-2004, 17:56
Questo è il mio output con parametro "25"...
VegetaSSJ5
17-09-2004, 17:59
Originariamente inviato da ilsensine
Questo è il mio output con parametro "25"...
che diavolo è quello schifo???:confused: a me sembra andare bene nel senso che le cose le stampa una volta sola nel momento in cui deve stamparle. se toglo quella wait il programma termina con successo. mi dà l'errore su quella wait ma per il resto sembra andare bene, non mi so spiegare cosa diavolo succede dentro al tuo computer...:confused: :confused:
VegetaSSJ5
17-09-2004, 18:06
ecco invece il mio output passandogli 3
ilsensine
17-09-2004, 18:10
Mio output con 3.
NB Per rendere più sequenziali gli output, ho sostituito le printf (che sono bufferizzate) con delle fprintf(stderr, ...) mettendo questo all'inizio del file:
#define printf(x, arg...) fprintf(stderr, x, ##arg)
VegetaSSJ5
17-09-2004, 18:19
ma allora a te funziona!! come mai a me invece dà quell'errore sulla wait? porca pu.....
ilsensine
17-09-2004, 23:13
Mah forse lo stai lanciando da una console che smanetta con SIGCHILD...
Prova a lanciarlo da un comune xterm
VegetaSSJ5
19-09-2004, 20:48
ilsensine ho risolto il problema della wait, o quantomeno ho scoperto la causa: in pratica il programma padre faceva la wait quando tutti i figli avevano terminato l'esecuzione e rispondeva dando l'errore No child processes.
Ora però c'è un'altro problema: a quanto pare anche se io gli passo come parametro 10 lui mi genera un numero di figli minore di 10, questo poi provoca il fatto che quando i figli terminano, il padre fa di nuovo la wait e mi riesce il solito errore. Ma come mai se gli passo 10 non mi genera 10 figli? E' come se non facesse 10 fork, ma questo è imposibile visto che ho inserito un ciclo for. Ti riposto il codice corretto.
VegetaSSJ5
19-09-2004, 20:49
mi sono dimenticato l'allegato, eccolo:
ilsensine
19-09-2004, 21:55
Originariamente inviato da VegetaSSJ5
ilsensine ho risolto il problema della wait, o quantomeno ho scoperto la causa: in pratica il programma padre faceva la wait quando tutti i figli avevano terminato l'esecuzione e rispondeva dando l'errore No child processes.
E' perfettamente legale fare una wait su un pid terminato. Quando un figlio muore, rimane nello stato di zombie finché non viene chiamata la wait/waitpid. L'unica eccezione è smanettare con SIGCHLD.
L'altro codice lo esaminerò domani.
ilsensine
20-09-2004, 12:50
./corretto 10
Non saprei...
ilsensine
20-09-2004, 12:51
NB sicuro che questo codice è corretto?
ctl_arg.array=(unsigned short *) calloc (10, sizeof(unsigned short));
for (i=0; i<10; i++) ctl_arg.array[i]=1;
if (semctl(semaforo, 0, SETALL, ctl_arg) <0) {
perror("Errore nella chiamata a semctl -2-");
exit(-1);
}
Mi puzza di race (i client, creati poco sopra, potrebbero essere in esecuzione e in operazione sul semaforo...)
Che scopo ha questa parte di codice?
VegetaSSJ5
20-09-2004, 14:33
ilsensine devo ancora commentare il codice quindi ti spiego "a quattrocchi" cosa significa:semun ctl_arg;
ctl_arg.array=(unsigned short *) calloc (10, sizeof(unsigned short));
if (semctl(semaforo, 0, SETALL, ctl_arg) <0) {
perror("Errore nella chiamata a semctl -1-");
exit(-1);
}questa parte inizializza tutti i 10 semafori al valore 0, cioè ai valori del vettore ctl_arg.array, che siccomeè stato creato con una calloc avrà tutti zeri. in questo modo i figli appena creati si trovano il semaforo bloccato e si mettono in coda (ed effettivamente è ciò che acade).ctl_arg.array=(unsigned short *) calloc (10, sizeof(unsigned short));
for (i=0; i<10; i++) ctl_arg.array[i]=1;
if (semctl(semaforo, 0, SETALL, ctl_arg) <0) {
perror("Errore nella chiamata a semctl -2-");
exit(-1);
}questa parte invece assegna a tutti e 10 i semafori il valore 1, cioè il valoredi ctl_arg.array a cui è stato assegnato il valore 1 in tutti i membri attraverso il for. quindi tutti i processi figli che erano in coda ai semafori possono procedere con la spesa. il semaforo bilancia (che è uno solo) invece è stato inizializzato direttamente ad 1 tanto i processi fifli devono prima comprare qualcosa e poi usufruire della bilancia.
ilsensine il problema, a quanto mi è parso di capire sta nel fatto che il padre non crea tanti figli quanti ne dovrebbe creare, e questo è strano. è come se uscisse dal for nonostante i sia minore di N.
VegetaSSJ5
20-09-2004, 14:36
ilsensine anche a me se lancio il programma redirigendo lo stdout su un file di testo mi fa tutto quel casino (nonostante ho ridefinito la printf...), ma se mantengo lo stdout sul monitor le scritte vengono visualizzate bene.
ilsensine
20-09-2004, 14:46
Originariamente inviato da VegetaSSJ5
questa parte invece assegna a tutti e 10 i semafori il valore 1, cioè il valoredi ctl_arg.array a cui è stato assegnato il valore 1 in tutti i membri attraverso il for. quindi tutti i processi figli che erano in coda ai semafori possono procedere con la spesa.
Così scritto è un pozzo di race.
Utilizza questo:
for(i=0; i<10; ++i) v(semaforo, i);
ilsensine
20-09-2004, 20:17
Io tolgo le tende fino a sabato.
In bocca al Segmentation fault :D
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.