PDA

Visualizza la versione completa : [C] fork e strano problema


davidinho
07-07-2013, 00:37
Sto imparando ad utilizzare la funzione fork() perciò ho fatto un semplice programmino, in breve fa questo:
1-prende un valore qt da linea di comando
2-crea qt processi figli stampando una frase che mostra a video la loro effettiva creazione
3-per ogni figlio creato viene salvato il PID in un array
4-stampa l'elenco dei figli creati

int sezionePadre(int figli[], int nFiglio, int pid) //funziona eseguita dal processo padre per qt volte
{
printf(" "); // ********
figli[nFiglio]=pid;
return 0;
}

int sezioneFiglio() //funzione eseguita solo dai figli
{
printf("Sono %d, il figlio di %d\n", (int)getpid(), (int)getppid());
return 0;
}

int main(int argc, char** argv)
{
int qt=atoi(argv[1]); //numero di figli da creare
int i;
int figli[qt]; //array che conterrà i PID dei figli creati
int pid;
int ret=1; //valore che ritornerà alla fine del processo padre
for(i=0; i<qt; i++)
{
pid=(int)fork();
if(pid==0) return sezioneFiglio();
else if(pid>0) ret = sezionePadre(figli, i, pid);
else printf("Errore\n");
}
if(ret!=0) return ret;

for(i=0; i<qt; i++) wait(); // attende la fine di tutti i qt processi figli

// Stampa l'elenco dei figli
printf("Sono %d, il padre di ", (int)getpid());
for(i=0; i<qt; i++)
printf("%d ", figli[i]);
printf("\n");

return ret;
}

Ora il programma funziona correttamente tranne per la stampa finale dei figli, infatti il primo figlio risulta sempre avere PID=0, il tutto si corregge mettendo un semplice printf(" ") in sezionePadre come quello che ho inserito con il commento // ********

si corregge anche con uno sleep(1), insomma mi basta ritardare un minimo la funzione sezionePadre, ma come mai succede questo?

MItaly
07-07-2013, 20:25
Da un rapido esame del codice, non mi pare che sia possibile che ciò accada (né ho riscontrato il problema che dici eseguendo il programma in loop qualche migliaio di volte)... è esattamente questo il codice che stai eseguendo?

P.S.: ormai dovresti saperlo che il linguaggio di riferimento va indicato anche nel titolo... :fagiano:

davidinho
07-07-2013, 23:24
non avevo indicato il linguaggio nel titolo? scusate, di solito lo metto, evidentemente me ne sono dimenticato

Comunque si il codice è quello senza però il printf in terza riga che, come già detto, l'ho messo solo per far funzionare il programma, infatti se lo rallento con uno sleep o con quel printf funziona, altrimenti da il problema descritto

Se puoi prova ad eseguirlo cancellando il printf in terza riga e dimmi se ti funziona correttamente

MItaly
08-07-2013, 01:08
Dopo mezz'ora che non capivo ho scovato l'errore.
Il problema deriva dal fatto che stai usando wait senza passarle alcun argomento e non hai incluso l'header in cui viene dichiarata. Se includi <sys/types.h> e <sys/wait.h> e provi a compilare ottieni:


fork.c: In function ‘main’:
fork.c:42:5: error: too few arguments to function ‘wait’
In file included from fork.c:4:0:
/usr/include/x86_64-linux-gnu/sys/wait.h:114:16: note: declared here

e se non lo includi ma abiliti i warning che bisognerebbe sempre abilitare (-Wall e -Wextra) ottieni:


fork.c: In function ‘main’:
fork.c:21:5: warning: implicit declaration of function ‘atoi’ [-Wimplicit-function-declaration]
fork.c:42:5: warning: implicit declaration of function ‘wait’ [-Wimplicit-function-declaration]


In quest'ultimo caso, il compilatore si immagina che sia stata dichiarata una funzione wait che non accetta alcun parametro e restituisce un intero.
Il problema è che la "vera" wait, invece, si aspetta un parametro, ma il compilatore non piazza nulla nel registro in cui questa se lo aspetta (rdi su x86-64), per cui questa "pesca" l'ultimo valore che era rimasto lì; nel caso in cui in sezionePadre non facevi niente di particolare, in rdi rimaneva l'indirizzo dell'array figlio, per cui la wait andava a scrivere nel primo elemento di figlio il valore restituito dai figli - ovvero 0, da cui il messaggio che vedevi in output.

Questa storia insegna ad includere sempre i file in cui sono dichiarate le funzioni e ad abilitare sempre i warning. :mem:

davidinho
08-07-2013, 02:46
si hai ragione, da adesso allora aggiungo sempre le opzioni -Wall e -Wextra
anche in molto altri esercizi ho commesso lo stesso errore ma evidentemente sono stato sempee fortunato tranne sta volta :D

Loading