Newsgroup: it.comp.lang.c
Titolo: Dubbio sulla WAIT

Domandina per i più esperti di me:
quando un processo esegue wait(NULL) attende che uno qualsiasi dei
suoi figli termini, e allora dealloca le sue risorse;
se il figlio è gia morto, il processo non si blocca su
quell'istruzione e, nel caso in cui il processo abbia un solo
figlio,termina e le risorse del figlio vengono deallocate.
Se quel processo possiede più figli, quando esegue wait(NULL) e tutti
i figli sono già morti, dealloca le risorse di un figlio qualsiasi?
Quindi se esegue tante wait(NULL) quanti i figli creati (nel caso in
cui i figli fossero già tutti morti quando esegue la prima
wait(NULL)), dealloca ad una ad una le risorse di TUTTI i figli?
Il dubbio mi è sorto risolvendo questo esercizio:
un processo padre crea un numero di figli specificato dall'utente.
Ciascuno di questi effettua una pausa casuale e termina. Il padre
termina solo quando tutti i suoi figli sono già terminati.
Le mie domande sopra si traducono quindi in questa: è corretta solo la
seconda versione(in cui uso la waitpid per ogni figlio, cosi sono
sicura di attenderli e deallocarli tutti), o anche la prima (in cui
uso tante volte la wait quante il numero di figli creati)?
prima versione:
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
int main (int argc, char **argv) {
	if (argc != 2) {
		printf("Utilizzo: nomeProgramma numeroFigli\n");
		exit(1);
	}
	int quantiFigli = atoi(argv[1]);
	printf("%d elementi sulla linea di comando\n",argc);
	printf("%d figli\n",quantiFigli);
	pid_t pid;
	int count=0;
	int casual;
	/*wait(NULL);*/
	while(count!=quantiFigli){
		if((pid=fork())<0) {
			fprintf(stderr,"fork fallita\n");
			exit(1);
		}
		else if (pid==0) {
			/*srandom(getpid());*/
			srandom(time());
			casual=1+random()%10;
			printf("Figlio %d si addormenta...\n",count+1);
			sleep(casual);
			printf("Figlio %d si è svegliato e esce.\n",count+1);
			exit(0);
		}
		else {
			count++;
		}
	}
	/*sleep(15);*/
	while(count!=0) {
		wait(NULL);
		count--;
	}
	printf("Ora che sono terminati tutti i miei figli posso terminare
anche io!\n");
	exit(0);
}
seconda versione:
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <sys/types.h>
int main (int argc, char *argv[]) {
	int count=0;
	int i=0;
	int casual;
	pid_t pid;
	if(argc!=2) {
		fprintf(stderr,"Utilizzo: nomeProgramma numeroFigliDaCreare\n");
		exit(1);
	}
	count=atoi(argv[1]);
	pid_t pidFigli[count];
	while(count>0) {
		if((pid=fork())<0) {
			fprintf(stderr,"Fork fallita!\n");
			exit(2);
		}
		else if (pid==0) {
			srandom(time());
			casual=1+random()%10;
			printf("Figlio %d si addormenta...\n",getpid());
			sleep(casual);
			printf("Figlio %d si sveglia e esce.\n",getpid());
			exit(0);
		}
		else {  pidFigli[i]=pid;
			i++;
			count--;
		}
	}
	while (count<i) {
		waitpid(pidFigli[count],NULL,0);
		printf("Il figlio %i è terminato!\n",pidFigli[count]);
		count++;
	}
	printf("Ora che sono terminati tutti i miei figli posso terminare
anche io!\n");
	exit(0);
}
Mary

 quell'istruzione e,
Il processo quell'istruzione la fa proprio quando il figlio termina.
Per quello che ho capito sei confusa con la wait e la waitpid.Comunque in 
pratica succede questo ;quando un processo termina il s.o. mantiente ancora 
delle tabelle
sul suddetto processo, il processo viene detto "zombies" (che fantasia gli 
americani..) fino a quando il processo padre non fa il reaping.
spero che questi esempi , presi dal libero dil Bryant O'hallaron, ti 
chiariscano le idee :
void fork7()
{
if (fork() == 0) {
/* Child */
printf("Terminating Child, PID = %d\n",getpid());
exit(0);
} else {
printf("Running Parent, PID = %d\n",getpid());
while (1)
; /* Infinite loop */
}
}
Se esegui questo programma in foreground .
linux> ./forks 7 &
[1] 6639
Running Parent, PID = 6639
Terminating Child, PID = 6640
Se vedi i processi in esecuzione :
linux> ps
    PID TTY TIME CMD
    6585 ttyp9 00:00:00 tcsh
    6639 ttyp9 00:00:03 forks
    6640 ttyp9 00:00:00 forks <defunct>
    6641 ttyp9 00:00:00 ps
vedi che il processo figlio, anche se terminato, è uno "zombie"
linux> kill 6639
[1] Terminated
Se uccidi il padre il reaping(per tutte e due) lo fa la shell per te..
linux> ps
PID TTY TIME CMD
6585 ttyp9 00:00:00 tcsh
6642 ttyp9 00:00:00 ps
La wait, sospende il padre fino a quando un figlio non ritorna il valore 
della exit (fa il reaping)
void fork7_m()
{
int status;
if (fork() == 0) {
/* Child */
printf("Terminating Child, PID = %d\n",getpid());
exit(0);
} else {
printf("Running Parent, PID = %d\n",getpid());
wait(&status);
while (1)
; /* Infinite loop */
}
}
Se esegui questo programma in foreground .
linux> ./forks 7_m &
[1] 6639
Running Parent, PID = 6639
Terminating Child, PID = 6640
Se vedi i processi in esecuzione :
linux> ps
    PID TTY TIME CMD
    6585 ttyp9 00:00:00 tcsh
    6639 ttyp9 00:00:03 forks
    6641 ttyp9 00:00:00 ps
lo zombie non c'è più.
Il problema è quando vi sono multipli figli ; la wait fa il reaping in 
ordine arbitrari, il primo processo che termina viene *rappato*:
es.
void fork10()
{
pid_t pid[N];
int i;
int child_status;
        for (i = 0; i < N; i++)
            if ((pid[i] = fork()) == 0)
                    exit(100+i); /* Child */
    for (i = 0; i < N; i++) {
    pid_t wpid = wait(&child_status);
        if (WIFEXITED(child_status))
printf("Child %d terminated with exit status %d\n",wpid, 
WEXITSTATUS(child_status));
else
printf("Child %d terminate abnormally\n", wpid);
    }
}
output potrebbe essere:
Child 3565 terminated with exit status 103
Child 3564 terminated with exit status 102
Child 3563 terminated with exit status 101
Child 3562 terminated with exit status 100
Child 3566 terminated with exit status 104
La waipid, aspetta un processo con un particolare pid, esempio se vogliamo 
fare il reaping non in ordine arbitrario ma in ordine di creazione ; faccio 
il reaping prima del figlio con stato 100 poi 101 e cosi via :
void fork11()
{
pid_t pid[N];
int i;
int child_status;
            for (i = 0; i < N; i++)
                if ((pid[i] = fork()) == 0)
                    exit(100+i); /* Child */
    for (i = 0; i < N; i++) {
    pid_t wpid = waitpid(pid[i], &child_status, 0);  // ASPETTO I FIGLI IN 
ORDINE
            if (WIFEXITED(child_status))
            printf("Child %d terminated with exit status %d\n",wpid, 
WEXITSTATUS(child_status));
            else
            printf("Child %d terminated abnormally\n", wpid);
}
l'output sarà :
Child 3568 terminated with exit status 100
Child 3569 terminated with exit status 101
Child 3570 terminated with exit status 102
Child 3571 terminated with exit status 103
Child 3572 terminated with exit status 104
ciao Spero di non averti confuso e sopra. di aver risposto al tuo dilemma
ciao
P.S. gli esempi sono stati presti dal libro di Bryant O'hallaron, 
compratevelo è ottimo .
--
Raffy