PDA

View Full Version : [C-UNIX]Padre figlio nipote e tutti i parenti


MEMon
15-03-2007, 15:16
Se ho un processo padre che genera N processi figli con la funzione fork(), se dopo la creazione di tutti i figli invoco un wait(&status), il padre aspetta la fine di TUTTI i figli, solo del primo, o solo dell'ultimo?

Come posso fare per avere un valore di ritorno da tutti i figli ed utilizzarlo nel padre? status del wait immagino non possa tenere traccia di tutti gli exit() dei figli, vero?

Se gli N figli generano a sua volta N figli(nipoti del padre :D), un wait invocato nel padre dopo la creazione di N figli cosa aspetta? anche la fine dei nipoti?

andbin
15-03-2007, 15:37
Se ho un processo padre che genera N processi figli con la funzione fork(), se dopo la creazione di tutti i figli invoco un wait(&status), il padre aspetta la fine di TUTTI i figli, solo del primo, o solo dell'ultimo?Il primo child che termina (che non è detto che sia il primo creato).

Come posso fare per avere un valore di ritorno da tutti i figli ed utilizzarlo nel padre? status del wait immagino non possa tenere traccia di tutti gli exit() dei figli, vero?Beh, tu sai quanti figli hai creato, quindi potresti fare un loop in cui chiami la wait() finché hai dei figli. Così prendi lo status di ognuno secondo la loro sequenza di terminazione.

Se gli N figli generano a sua volta N figli(nipoti del padre :D), un wait invocato nel padre dopo la creazione di N figli cosa aspetta? anche la fine dei nipoti?No, solo dei propri figli. Dopotutto un padre potrebbe anche non sapere cosa fanno i figli!

MEMon
15-03-2007, 15:39
Grazie andbin, ok quindi faccio un while finchè ho figli attivi, però, x aspettare anche i nipoti l'unico modo è quindi non far terminare il figlio che ha creato il nipote, giusto?

andbin
15-03-2007, 15:54
x aspettare anche i nipoti l'unico modo è quindi non far terminare il figlio che ha creato il nipote, giusto?Un processo può solo attendere la fine dei propri figli (non dei "nipoti"). Se un processo figlio termina, allora sei sicuro che pure i nipoti sono terminati.

MEMon
15-03-2007, 15:57
Un processo può solo attendere la fine dei propri figli (non dei "nipoti"). Se un processo figlio termina, allora sei sicuro che pure i nipoti sono terminati.

Si ma si è sicuro solo nel caso in cui anche il figlio è in wait si suo figlio(nipote).

Io ho il padre in attesa dei figli con un ciclo while:

while(pid=wait(&status)!=-1){
printf("%d", pid);
}


Mi da sempre come valore 1, non dovrebbe darmi il pid del figlio appena terminato?

andbin
15-03-2007, 16:37
while(pid=wait(&status)!=-1){

Mi da sempre come valore 1, non dovrebbe darmi il pid del figlio appena terminato?Così come hai messo il test, fa prima wait(&status)!=-1, quindi il risultato (un 1/0 se vero/falso) lo assegna a pid!!!

while((pid=wait(&status)) != -1){

MEMon
15-03-2007, 17:18
Si è vero...che errore del menga :(

Per fare comunicare padre e figlio posso sia usare le pipe che mettere in comune aree di memoria con i puntatori vero?

andbin
15-03-2007, 19:38
Per fare comunicare padre e figlio posso sia usare le pipe che mettere in comune aree di memoria con i puntatori vero?Con le pipe certamente. Con aree di memoria no .... a meno di usare le funzioni apposite per la gestione dei "shared memory segment" (vedi le funzioni shmget/shmctl/shmat/shmdt).

Tieni presente che quando fai fork(), i due processi padre e figlio effettivamente hanno la stessa "visione" dello spazio di indirizzamento ma la cosa è dovuta solo ad una questione di ottimizzazione. Viene usata la tecnica del copy-on-write (vedi <qui> (http://en.wikipedia.org/wiki/Copy-on-write)), in pratica le pagine logiche di padre e figlio sono condivise ma alla prima scrittura da parte di uno dei due, la pagina viene duplicata (e quindi separata tra padre e figlio).
Per tale motivo non ci può essere comunicazione "diretta" tramite la memoria tra padre e figlio.

MEMon
15-03-2007, 20:36
Ho capito, ma se un figlio scrive ad un certo indirizzo di memoria una variabile(usa un puntatore quindi),quando poi qualche altro processo(padre,figlio o nipote che sia) legge quella parte di memoria, utilizzando sempre un puntatore, non legge la variabile scritta dal processo precedentemente?

andbin
16-03-2007, 08:22
Ho capito, ma se un figlio scrive ad un certo indirizzo di memoria una variabile(usa un puntatore quindi),quando poi qualche altro processo(padre,figlio o nipote che sia) legge quella parte di memoria, utilizzando sempre un puntatore, non legge la variabile scritta dal processo precedentemente?No. Prova il seguente programmino:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main (void)
{
pid_t p;
int status;
int var;

var = 10;

p = fork ();

if (p == 0)
{
/* figlio */
printf ("[figlio] var = %d\n", var);
var = 20;
printf ("[figlio] var = %d\n", var);
sleep (5);
printf ("fine figlio\n");
}
else if (p != -1)
{
/* padre */
sleep (2);
printf ("[padre] var = %d\n", var);

wait (&status);
printf ("fine padre\n");
}

return 0;
}Stampa:
[figlio] var = 10
[figlio] var = 20
[padre] var = 10
fine figlio
fine padre

Questo perché dopo la fork sia padre che figlio "vedono" lo stesso spazio di memoria ma quando il figlio imposta la variabile 'var' la modifica vale solo per lui e non per il padre.

MEMon
16-03-2007, 09:24
Convinto :D
andbin fino ad ora provavo con cygwin(l'emulatore di un sistumea unix per windows) solo che la funzione lseek sembra non funzionare(forsa anche a causa delle partizioni ntfs bho), allora ho provato una versione live di ubuntu.
Solo che non mi compila, non trova gli include, devo impostare qualcosa?
Per compilare faccio:
gcc -o filecompilato file.c

andbin
16-03-2007, 09:50
la funzione lseek sembra non funzionare(forsa anche a causa delle partizioni ntfs bho), allora ho provato una versione live di ubuntu.
Solo che non mi compila, non trova gli include, devo impostare qualcosa?Questo semplice programmino stampa la lunghezza di un file:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>

int main (int argc, char *argv[])
{
int fd;
off_t offset;

if ((fd = open (argv[1], O_RDONLY)) != -1)
{
offset = lseek (fd, 0, SEEK_END);
printf ("%d\n", offset);
close (fd);
}

return 0;
}Compilato semplicemente con: gcc -o prova prova.c

MEMon
16-03-2007, 09:54
azz sisi, ho visto che hai aggiunto #include <unistd.h>
senza quello non funziona mi da -1 senza dare però errore di mancanza di qualche include...
E con perror mi dice Invalid Argument nella funzione lseek...per quello non sapevo cosa fare!

Quindi quello che mi mancava era quell'include!
Grazie mille come al solito!!!

MEMon
16-03-2007, 11:43
Se dovessi passare una struttura tra padre e figlio come faccio?
Con le pipe immagino che non posso vero?
E siccome mi hai detto che per spazio di memoria non si può che soluzione devo adottare?

andbin
16-03-2007, 12:01
Se dovessi passare una struttura tra padre e figlio come faccio?Se devi passare un qualcosa da padre a figlio una volta sola e basta, è sufficiente che fai come nel mio esempio sopra. 'var' infatti viene visto anche dal figlio.

Con le pipe immagino che non posso vero?Certo che puoi. Una pipe devi vederla alla stessa stregua di un descrittore per un normale file. Da una parte scrivi, dall'altra leggi. È chiaro che padre e figlio devono "accordarsi" su cosa/come passarsi i dati.

Scrivi la struttura (N byte quindi) sulla pipe e dall'altra parte si leggono N byte.

E siccome mi hai detto che per spazio di memoria non si può che soluzione devo adottare?Puoi anche usare le funzioni shmXXX che ho citato prima.

MEMon
16-03-2007, 12:03
Si ma quello che non capisco è se la struttura che scrivo sulla pipe, quando poi dall'altra parte la vado a leggere come faccio a ricostruirla?
Cioè immagino che io leggo una serie di byte, come faccio a sapere che sono di una struttura, e come faccio quindi a riformarla?

andbin
16-03-2007, 12:15
Si ma quello che non capisco è se la struttura che scrivo sulla pipe, quando poi dall'altra parte la vado a leggere come faccio a ricostruirla?
Cioè immagino che io leggo una serie di byte, come faccio a sapere che sono di una struttura, e come faccio quindi a riformarla?MIASTRUCT s;
write (fd, &s, sizeof (s));

e poi

read (fd, &s, sizeof (s));

Dove fd può essere un qualunque descrittore. Il concetto è che stai scrivendo/leggendo un blocco di bytes.

MEMon
16-03-2007, 12:36
perfetto, se ho N figli, e ognuno deve passare una struttura al padre, mi basta una pipe (int piped[2]) o me ne serve una per ogni processo figlio (matrice di pipe)?

andbin
16-03-2007, 12:42
perfetto, se ho N figli, e ognuno deve passare una struttura al padre, mi basta una pipe (int piped[2]) o me ne serve una per ogni processo figlio (matrice di pipe)?Se usi la funzione pipe(), va bene solo per una comunicazione 1:1. Se più processi devono comunicare con un altro processo, ti conviene usare una FIFO.

Comunque leggi <qui> (http://www.gnu.org/software/libc/manual/html_node/Pipes-and-FIFOs.html#Pipes-and-FIFOs), perché su 'ste cose non sono ferratissimo!

MEMon
16-03-2007, 12:58
Ho fatto una prova, ho creato una sola pipe,e poi ho fatto scrivere ogni figlio dentro quella pipe.
Quando poi sono terminati tutti i figli, ho fatto leggere al padre il contenuto della pipe, e c'erano tutti i caratteri scritti in ordine di scrittura.
Quindi immagino che sia come un recipiente in "comunione" o no?
Da quel che ho capito i descrittori di file, come anche le pipe quindi, create dal padre sono usabili anche dai figli.

andbin
16-03-2007, 13:29
Ho fatto una prova, ho creato una sola pipe,e poi ho fatto scrivere ogni figlio dentro quella pipe.
Quando poi sono terminati tutti i figli, ho fatto leggere al padre il contenuto della pipe, e c'erano tutti i caratteri scritti in ordine di scrittura.
Quindi immagino che sia come un recipiente in "comunione" o no?Quindi, fammi capire: hai chiamato la pipe() prima di fare le fork() e poi nei figli usi lo stesso identico filedes[1] per scrivere sulla pipe??
Uhm ... potrebbe funzionare, salvo questioni di atomicità.

Ho letto che:
Reading or writing pipe data is atomic if the size of data written is not greater than PIPE_BUF. This means that the data transfer seems to be an instantaneous unit, in that nothing else in the system can observe a state in which it is partially complete. Atomic I/O may not begin right away (it may need to wait for buffer space or for data), but once it does begin it finishes immediately.

PIPE_BUF, da quello che ho visto negli include, vale 4096.

MEMon
16-03-2007, 13:32
sisi esatto proprio così, ho fatto una prova con le stringhe e funziona, quindi siccome è atomica direi che posso farlo in tutta tranquillità giusto?

Ho problemi a trasferire strutture, ho creato un altro thread apposito però se puoi darci un'occhio visto che per te saranno bazzecole :D