PDA

View Full Version : [C] Dubbio su pipe


VegetaSSJ5
02-07-2004, 21:24
Salve a tutti, la mia domanda è questa.
Ho creato 2 pipe, una per comunicare verso un processo padre e un'altra dal padre ai figli. Nel codice del padre a questo punto eseguo N fork() per creare altrettanti figli. Questi figli avranno a disposizione queste pipe. A questo punto se io per ogni figlio mando un messaggio al padre attraverso la pipe, il padre riceverà TUTTI i messaggi dei figli (in modo fifo, per poi poterli processare in sequenza)? Ricordo che ogni figlio ha una pipe per comunicare con il padre, com'è possibile che se ognuno ha la sua pipe, il padre riceve i messaggi in un'unica pipe? E se invece il padre manda un messaggio nella pipe per comunicare con i figli (ricordo che ogni figlio ha la sua, a causa della fork), i figli (TUTTI) riceveranno il messaggio nella pipe? Se fosse così se un figlio fa la read() sulla pipe, quel messaggio verrebbe cancellato (cioè il puntatore si sposterebbe di size byte, cmq non stiamo a dilungarci su queste cose) e non sarebbe più a disposizione degli altri figli giusto? Oppure succede che un figlio fa la read ma cancella solo il messaggio nella sua pipe a non anche in quelle degli altri?

Scusate ragazzi se faccio queste domende idiote, rileggendo mi sembro un idiota anch'io, ma poi con il fatto delle tante fork() non ho capito come si organizzano le pipe.

Ed_Bunker
03-07-2004, 02:12
Da quel che ho capito stai parlando di pipe senza nome. O no ? Non credo che sia possibile fare un "protocollo" client-server con pipe senza nome poiche' i descrittori di file sono condivisi e pertanto se tutti devono leggere e scrivere, tali letture e tali scritture non possono essere "controllate". Anche se e' possibile fare in modo che solo il processo padre riceva tutte le richieste dei figli... Cio' che non e' possibile e fare in modo che il padre invii le risposte riuscendo a distinguere i vari processi figli. A meno di utilizzare, forse, un semaforo con il quale i processi sincronizzino le loro letture (Supponendo che debbano avvenire in un certo ordine...). Solitamente le pipe senza nome tornano bene quando si deve far comunicare un solo processo padre con un solo processo figlio. A questo modo uno dei due manterra' aperta la pipe in scrittura mentre l'altro la manterra' aperta in lettura. A questo punto potranno comunicare.
Se vuoi fare un modello client server credo sia piu' opportuno utilizzare pipe con nome. Ogni client avra' una pipe su cui leggere (Le risposte del server) mentre il processo padre (Server) avra' una sola propria pipe sulla quale ricevere le richieste da parte di tutti i figli.

Credo che le cose stiano cosi ma... magari ho sparato qualche minc**** !

VegetaSSJ5
03-07-2004, 12:41
secondo te allora (al posto delle pipe) è meglio utilizzare le socket?

Ed_Bunker
03-07-2004, 13:18
Originariamente inviato da VegetaSSJ5
secondo te allora (al posto delle pipe) è meglio utilizzare le socket?
Secondo me la cosa piu' semplice e' utilizzare delle pipe con nome. Una per ciascun processo. Il processo padre utilizza la sua pipe con nome per ricevere le richieste dai processi figli. I processi figli ricevono le risposte dal processo padre leggendo dalla loro pipe con nome. Probabilmente ci saranno diverse altre possibilita' ma questa credo sia la piu' sempolice...

VegetaSSJ5
03-07-2004, 14:58
Originariamente inviato da Ed_Bunker
Secondo me la cosa piu' semplice e' utilizzare delle pipe con nome. Una per ciascun processo. Il processo padre utilizza la sua pipe con nome per ricevere le richieste dai processi figli. I processi figli ricevono le risposte dal processo padre leggendo dalla loro pipe con nome. Probabilmente ci saranno diverse altre possibilita' ma questa credo sia la piu' sempolice...
il fatto è che i messaggi che deve inviare il padre non li deve inviare ad un processo in particolare, ma a tutti quanti, quindi le pipe con nome sono inutili in questo caso.

Ed_Bunker
03-07-2004, 18:05
Originariamente inviato da VegetaSSJ5
il fatto è che i messaggi che deve inviare il padre non li deve inviare ad un processo in particolare, ma a tutti quanti, quindi le pipe con nome sono inutili in questo caso.

Se il padre conosce le pipe di tutti i figli basta che invii il solito messaggio n volte su n pipe (con nome) differenti. Altrimenti resta la possibilita' di usare pipe senza nome e fare in modo che i figli si sincronizzino nelle letture (Se il messaggio e' lo stesso per tutti allora non occorre neppure sincronizzazione) e che il padre invii n volte il messaggio. Io credevo che i messaggio inviati dal padre fossero differenti a seconda del figlio.

VegetaSSJ5
03-07-2004, 21:19
allora cerco di spiegare la situazione il + semplicemente possibile. il padre produce un messaggio e lo mette in una scatola. tutti i figli vanno a leggere cosa c'è in quella scatola. quando il padre riproduce un nuovo messaggio lo mette nella scatola cancellando quello che c'era prima. per implementare questa cosa sarebbe stato semplicissimo farlo con un segmento di memoria condivisa, che ho già usato per altre cose nello stesso programma. tuttavia nelle specifiche del progetto c'è scritto che lo scambio di messaggi tra il padre e i figli deve essere realizzato tramite socket o pipe, quindi non posso usare la memoria condivisa. hai qualche idea? (magari anche un po' di codice di esempio?)

Ed_Bunker
03-07-2004, 22:22
Originariamente inviato da VegetaSSJ5
allora cerco di spiegare la situazione il + semplicemente possibile. il padre produce un messaggio e lo mette in una scatola. tutti i figli vanno a leggere cosa c'è in quella scatola. quando il padre riproduce un nuovo messaggio lo mette nella scatola cancellando quello che c'era prima. per implementare questa cosa sarebbe stato semplicissimo farlo con un segmento di memoria condivisa, che ho già usato per altre cose nello stesso programma. tuttavia nelle specifiche del progetto c'è scritto che lo scambio di messaggi tra il padre e i figli deve essere realizzato tramite socket o pipe, quindi non posso usare la memoria condivisa. hai qualche idea? (magari anche un po' di codice di esempio?)

Ok adesso le cose sono piu' chiare. Mi viene da dire che in questo caso l'utilizzo di pipe (O di socket) non sia l'ideale poiche' i messaggi vengono consumati dai figli mentre tu vorresti che il messaggio venisse soltanto letto e potesse essere sovrascritto unicamente dal padre (Per inviare i messaggi successivi). Istintivamente credo che la soluzione sia quella di usare memoria condivisa abbinata all'utilizzo di semafori (Per impedire che i processi figli vadano a leggere mentre il padre sta scrivendo un nuovo messaggio).

Pero' se il testo dice di usare pipe o socket...

VegetaSSJ5
04-07-2004, 13:05
Originariamente inviato da Ed_Bunker
Pero' se il testo dice di usare pipe o socket...
:cry: :cry:
http://www.di.univaq.it/~formisano/lso0304/pro5.txt

Ed_Bunker
04-07-2004, 14:35
Originariamente inviato da VegetaSSJ5
:cry: :cry:
http://www.di.univaq.it/~formisano/lso0304/pro5.txt

Eh gia'... Ho appena letto. Prova a mandare una e-mail al tuo professore (Sperando che sia "gentile"...). Anch'io sto facendo un progetto in C ed ho letteralmente sommerso di posta il mio docente. :D

VegetaSSJ5
04-07-2004, 15:49
non si può fare in modo che un figlio quando va a leggere in una pipe non cancella il messaggio (in quanto la read "cancella" il messaggio che legge, ma che poi verrà sovrascritto dal padre quando farà la write) e quindi questo sarà disponibile anche per gli altri processi che leggono?

Ed_Bunker
04-07-2004, 17:50
Originariamente inviato da VegetaSSJ5
non si può fare in modo che un figlio quando va a leggere in una pipe non cancella il messaggio (in quanto la read "cancella" il messaggio che legge, ma che poi verrà sovrascritto dal padre quando farà la write) e quindi questo sarà disponibile anche per gli altri processi che leggono?
Che io sappia no. Magari potresti leggere dalla pipe e riscrivere sulla pipe stessa quello che hai appena letto permettendo agli altri processi di leggere (Visto che il mess. e' uguale per tutti). Pero' non mi sembra affatto una soluzione 'buona' ed inoltre si potrebbe ancora andare incontro a problemi di interferenza. Non saprei...

VegetaSSJ5
05-07-2004, 12:38
Originariamente inviato da Ed_Bunker
Che io sappia no. Magari potresti leggere dalla pipe e riscrivere sulla pipe stessa quello che hai appena letto permettendo agli altri processi di leggere (Visto che il mess. e' uguale per tutti). Pero' non mi sembra affatto una soluzione 'buona' ed inoltre si potrebbe ancora andare incontro a problemi di interferenza. Non saprei...
si potrebbe fare questo con i socket?

Ed_Bunker
05-07-2004, 13:07
Originariamente inviato da VegetaSSJ5
si potrebbe fare questo con i socket?

Si, in pratica i socket sono soltanto delle pipe (Notevolmente) "piu' evolute"... Per quello che devi fare tu penso sia piu' semplice utilizzare le pipe.

x110
05-07-2004, 14:16
man dup2 per duplicare i file descriptor

puoi sicuramente fare una lettura da un file(pipe) senza toglierci i dati che ci sono dentro,
devi modificare il file descriptor con la ioctl, sinceramente non so come ma la strada e' quella
per esempio per leggere quanti dati ci sono nella porta seriale o in un fd senza modificarne il contenuto si fa

ioctl(fd_com,FIONREAD,&bytes);

e ti restituisce il n° di byte presenti, per leggere il buffer devi mettere qualcosa di diverso da fionread ma sinceramente non so bene se mi ricordassi o trovassi qualche cosa....

x110
05-07-2004, 15:31
e' tipo un poke.
ma non mi sovviene.......

-----scanning in progress------

Ed_Bunker
05-07-2004, 15:59
Originariamente inviato da x110
man dup2 per duplicare i file descriptor

puoi sicuramente fare una lettura da un file(pipe) senza toglierci i dati che ci sono dentro,
devi modificare il file descriptor con la ioctl, sinceramente non so come ma la strada e' quella
per esempio per leggere quanti dati ci sono nella porta seriale o in un fd senza modificarne il contenuto si fa

ioctl(fd_com,FIONREAD,&bytes);

e ti restituisce il n° di byte presenti, per leggere il buffer devi mettere qualcosa di diverso da fionread ma sinceramente non so bene se mi ricordassi o trovassi qualche cosa....

La lettura da una pipe dovrebbe consumare cmq. i bytes al suo interno (O per lo meno parte di essi).

x110
05-07-2004, 16:03
se la fai con la read sicuramente si...

VegetaSSJ5
05-07-2004, 20:18
Originariamente inviato da x110
se la fai con la read sicuramente si...
sai se esiste una funzione che al contrario della read non consuma i bytes??

x110
06-07-2004, 11:01
si, sembro un deficente perche' non me la ricordo ma esiste,
se riesco a ricordarmi la posto.

Ed_Bunker
06-07-2004, 21:21
Originariamente inviato da x110
si, sembro un deficente perche' non me la ricordo ma esiste,
se riesco a ricordarmi la posto.

Mi sa proprio che sei il solito massese folone ... :D :D :D

x110
07-07-2004, 11:00
vedo che anche tu non scherzi.....
sei iscritto al lug?

Ed_Bunker
07-07-2004, 11:10
Originariamente inviato da x110
vedo che anche tu non scherzi.....
sei iscritto al lug?

No... Volevo iscrivermi al Gulp di Pisa e poi ho lasciato perdere... Sinceramente nemmeno sapevo del LUG di Massa (Sto guardando proprio adesso la home page www.tivedotonico.it)

P.S.: che bel nome per la homepage ! :D

x110
07-07-2004, 18:22
non e' che sia pieno..... comunque.
io tral'altro sono della lunigiana, un po' staccato.

ciao.

VegetaSSJ5
10-07-2004, 17:58
ragazzi scusate ma sono nella merd@...:cry:
evidentemente la strada che ho intrapreso per svolgere il progetto non era quella giusta (pipe senza nome), per questo vi chiedo di farmi un esempio di pipe con nome. cioè il padre per ogni figlio che crea (in un ciclo for ad esempio), crea anche una pipe con nome per poter comunicare con lui. qualcuno può farmi un esempietto di come si fa? grazie...

Ed_Bunker
10-07-2004, 19:49
Originariamente inviato da VegetaSSJ5
ragazzi scusate ma sono nella merd@...:cry:
evidentemente la strada che ho intrapreso per svolgere il progetto non era quella giusta (pipe senza nome), per questo vi chiedo di farmi un esempio di pipe con nome. cioè il padre per ogni figlio che crea (in un ciclo for ad esempio), crea anche una pipe con nome per poter comunicare con lui. qualcuno può farmi un esempietto di come si fa? grazie...

Le pipe con nome si creano semplicemente con la chiamata "mkfifo" a cui devi indicare il nome da dare alla pipe e la modalita' con cui potra' essere aperta da altri processi. Ad esempio potresti fare:

...
...
int pid;
int i;
for (i=0; i < N; i++)
{
if ((pid = fork()) == -1)
{
perror("Errore nella fork");
exit(-1);
}
if (pid) /*PADRE*/
{ /*Fai quello che vuoi...*/}
else /*FIGLIO*/
{
char * nomePipe = (char) malloc(sizeof(int) + 2);
sprintf(nomePipe,"%d.p",getpid());
/*La pipe del processo si chiamera' 'nomePipe'
dove pid e' il pid del processo figlio in questione*/
/*Adesso crei la pipe ...*/
if (mkfifo(nomePipe, 0644) == -1)
{
perror("Errore creazione pipe con nome");
exit(-1);
}

/Esempio di apertura in lettura*/
int fd;
if ((fd = open(nomePipe, O_WRONLY)) == -1)
{
perror("Errore apertura pipe");
exit(-1);
}
....
....
unlink(nomePipe);/*Elimini la pipe dal filesystem*/
exit(0);/*Il figlio esce inviando un SIGCHLD al proc. padre*/
}
...
...
}


A mio parere l'utilizzo di pipe con nome e' piu' semplice di quello senza nome. Hai provato a chiedere qualche suggerimento al tuo prof ?! Non ti cag* neanche quello ?!? :D :D

VegetaSSJ5
11-07-2004, 13:38
Originariamente inviato da Ed_Bunker
Le pipe con nome si creano semplicemente con la chiamata "mkfifo" a cui devi indicare il nome da dare alla pipe e la modalita' con cui potra' essere aperta da altri processi. Ad esempio potresti fare:

...
...
int pid;
int i;
for (i=0; i < N; i++)
{
if ((pid = fork()) == -1)
{
perror("Errore nella fork");
exit(-1);
}
if (pid) /*PADRE*/
{ /*Fai quello che vuoi...*/}
else /*FIGLIO*/
{
char * nomePipe = (char) malloc(sizeof(int) + 2);
sprintf(nomePipe,"%d.p",getpid());
/*La pipe del processo si chiamera' 'nomePipe'
dove pid e' il pid del processo figlio in questione*/
/*Adesso crei la pipe ...*/
if (mkfifo(nomePipe, 0644) == -1)
{
perror("Errore creazione pipe con nome");
exit(-1);
}

/Esempio di apertura in lettura*/
int fd;
if ((fd = open(nomePipe, O_WRONLY)) == -1)
{
perror("Errore apertura pipe");
exit(-1);
}
....
....
unlink(nomePipe);/*Elimini la pipe dal filesystem*/
exit(0);/*Il figlio esce inviando un SIGCHLD al proc. padre*/
}
...
...
}


A mio parere l'utilizzo di pipe con nome e' piu' semplice di quello senza nome. Hai provato a chiedere qualche suggerimento al tuo prof ?! Non ti cag* neanche quello ?!? :D :D
quello non cag@ nessuno! cmq dal codice che hai scritto qui sopra la pipe con nome viene creata dal figlio e non dal padre. in questo modo come riusciranno a comunicare i due processi? il permesso 0644 di mkfifo cosa significa? perchè nel puntatore a caratteri nomepipe di ci scrivi il pid del processo figlio?

Ed_Bunker
11-07-2004, 14:20
Originariamente inviato da VegetaSSJ5
quello non cag@ nessuno! cmq dal codice che hai scritto qui sopra la pipe con nome viene creata dal figlio e non dal padre. in questo modo come riusciranno a comunicare i due processi? il permesso 0644 di mkfifo cosa significa? perchè nel puntatore a caratteri nomepipe di ci scrivi il pid del processo figlio?

La pipe puoi farla creare anche al padre. Dipende da come tu ritieni che sia preferibile fare e dal contesto in cui deve avvenire la comunicazione. Dando il nome della pipe in funzione del pid del processo il padre potra' sempre sapere su quale pipe inviare i messaggi controllando solo il pid del processo figlio. Ad esempio per inviare un msg al processo figlio con pid 3456 bastera' inviare un msg sulla pipe 3456.p... Per i msg. da figli a padre potra' essere utilizzata una pipe con nome chiamata ad esempio padre.p oppure il padre potra' leggere direttamente dalle pipe che i figli hanno creato (Anche qui dipende dalla specificita' del progetto).

0644 durante la creazione significa che la pipe puo' essere aperta sia in lettura che in scrittura.

VegetaSSJ5
11-07-2004, 15:06
Originariamente inviato da Ed_Bunker
La pipe puoi farla creare anche al padre. Dipende da come tu ritieni che sia preferibile fare e dal contesto in cui deve avvenire la comunicazione. Dando il nome della pipe in funzione del pid del processo il padre potra' sempre sapere su quale pipe inviare i messaggi controllando solo il pid del processo figlio. Ad esempio per inviare un msg al processo figlio con pid 3456 bastera' inviare un msg sulla pipe 3456.p... Per i msg. da figli a padre potra' essere utilizzata una pipe con nome chiamata ad esempio padre.p oppure il padre potra' leggere direttamente dalle pipe che i figli hanno creato (Anche qui dipende dalla specificita' del progetto).

0644 durante la creazione significa che la pipe puo' essere aperta sia in lettura che in scrittura.
ti ringrazio, ora mi è tutto più chiaro. un'ultima cosa: la pipe per comunicare con il padre, cioè padre.p, deve essere creata dal padre prima delle fork in modo tale che questa pipe venga ereditata anche ai figli giusto?

Ed_Bunker
11-07-2004, 15:53
Originariamente inviato da VegetaSSJ5
ti ringrazio, ora mi è tutto più chiaro. un'ultima cosa: la pipe per comunicare con il padre, cioè padre.p, deve essere creata dal padre prima delle fork in modo tale che questa pipe venga ereditata anche ai figli giusto?

Adesso ti picchio !!! :boxe: :D Ragioni ancora in termini di pipe senza nome. E' sufficiente che il padre crei la pipe con nome. Basta. A quel punto per il figlio sara' come aprire un semplice file poiche' la pipe si trovera' sul file system. Do You understand ?! Quindi il padre la crea fuori dal ciclo in cui esegue le fork(), se la apre in lettura. Invece ciascun figlio la aprira' in scrittura sapendone il nome NOTO (padre.p) Ok ? ;) :D

VegetaSSJ5
11-07-2004, 16:50
allora ho scritto la funzione per generare i figli e le relative pipes. pipe è una variabile globale dichiarata come char *pipe; inoltre il vettore automobili[] conterrà i pid delle auto create. ecco il codice:void genera_auto (int N, pid_t vigile) {
pipe= (char *) calloc (pipe, 7*sizeof(char));
sprintf(pipe,"padre.p");
if (mkfifo(pipetov, 0666) < 0) error("Errore nella creazione della pipe di comunicazione con il vigile");
int i=0;
for (i=0; i<N; i++) {
if (getpid()==vigile) {
printf("\nVIG: Sto generando l'auto numero %d...", i+1);
fflush(stdout);
if ((automobili[i]=(int)fork()) < 0) error("Errore generando l'automobile");
}
else {
pipe= (char *) calloc (pipe, sizeof(pid_t)+2);
sprintf(pipe, "%d.p", getpid());
if (mkfifo(pipe, 0666) < 0) error("Errore nella creazione della pipe di comunicazione con l'automobile");
i=N;
sleep(2);
}
}
}a questo punto se il padre vuole mandare un messaggio al figlio con pid 3122 come devo fare? e viceversa se un figlio deve mandare un messaggio al padre come devo fare? sò di aver rotto le OO ma ti prometto chese capisco questo non avrò + domande da farvi...;)

Ed_Bunker
11-07-2004, 17:04
Se il figlio deve mandare un msg al padre bastera' che faccia:

...
...
int fd;
if ((fd = open("padre.p", O_WRONLY)) == -1)
{ perror("Errore apertura pipe"); exit(-1);}
char * msg = "Ciao";
if (write(fd, msg, strlen(msg)) != strlen(msg)
{ perror("Errore in scrittura sulla pipe"); exit(-1);}
...
...


Mentre potra' mantenersi un array di interi dove sono contenuti i pid di tutti i figli. Ad ogni fork() inserisce il pid del figlio creato all'interno dell'array...
Per mandare un msg al pid 3122 (Te lo avevo gia' scritto prima !!! :muro: :D ) faro':


...
...
if (write("3122.p", msg, strlen(msg)) ! = strlen(msg))
{ perror("Errore sulla write"); exit(-1); }
...
...


Non capisco dove stia il problema a meno che tu non voglia avere la possibilita' di distinguere/riconoscere i processi figli in base a qualche "caratteristica"...

VegetaSSJ5
11-07-2004, 17:08
Ed_Bunker cosa posso fare per sdebitarmi con te (oltre che evitare di fare altre domande ;))?

Ed_Bunker
11-07-2004, 17:48
Originariamente inviato da VegetaSSJ5
Ed_Bunker cosa posso fare per sdebitarmi con te (oltre che evitare di fare altre domande ;))?

Niente di che... Mi basta che tu faccia anche il progetto che entro agosto devo consegnare io... :D :D
A parte gli scherzi... E' servito anche a me per rinfrescare l'argomento sulla comunicazione mediante pipe. ;)