View Full Version : [C] Attendere terminazione...
Ed_Bunker
07-07-2004, 17:21
Ciao, dovrei implementare un semplice server che, ricevendo richieste da una pipe nota, crei ad hoc dei processi per soddisfare tali richieste. Ad ogni richiesta, pero', il server (Il processo padre, non i figli !) deve mantenere una media del tempo di esecuzione necessario per soddisfare ciascuna richiesta. Avevo pensato di utilizzare la gettimeofday() prima di mandare in esecuzione il figlio e poi di utilizzare la sigaction() per fare in modo che, alla terminazione del figlio, il segnale SIGCHLD venga gestito mediante una routine apposita che faccia la "seconda" gettimeofday() e quindi permetta al padre di aggiornare tale media. Cosi' facendo, pero', non posso risalire a quale funzione sia stata svolta dal figlio e, pertanto, il server non sa quale delle medie andare ad aggiornare. Spero di essere stato chiaro... o di esserci andato vicino... Sapreste darmi qualche consiglio !?! Escludo l'utilizzo di wait() poiche' renderebbe vano l'utilizzo di processi appositi affinche' il processo padre possa ricevere nuove richieste.
thks
ilsensine
07-07-2004, 17:25
Invece devi usare proprio la wait o waitpid, altrimenti come fai a sapere quale pid ha generato il segnale?
Ed_Bunker
07-07-2004, 18:28
Originariamente inviato da ilsensine
Invece devi usare proprio la wait o waitpid, altrimenti come fai a sapere quale pid ha generato il segnale?
A me non interesserebbe sapere quale specifico pid abbia generato il segnale. Vorrei soltanto avere il modo di sapere quale funzione il figlio ha portato a termine.
Dovrebbe succedere qualcosa del genere:
...
int med1, med2, med3, med4;
/*Quattro differenti richieste. Per gni richiesta c'e'
una precisa funzione per soddisfarla...*/
/*Il padre riceve una richiesta e la codifica*/
pid = fork();
if (pid==0)/*Processo figlio*/
{
/*Esegue la funzione che il padre ha "deciso" debba essere seguita*/
}
else
{/*Processo padre*/
struct timeval t1, t2;
gettimeofday(&t1, NULL);
/*Va ad aspettare altre richieste ma e'
pronto a fare la seconda gettimeofday() quando
il figlio avra' terminato di eseguire la
funzione... ma come ?!?*/
....
....
:help: :help: :help: :help: :help:
Ed_Bunker
07-07-2004, 18:49
L'ideale sarebbe avere un modo per trasferire informazione ulteriore dal figlio al padre. Del tipo: quando il figlio termina, oltre ad inviare il SIGCHLD, invia al padre anche il num. che identifica la funzione eseguita ed il tempo che ha impiegato per eseguire tale funzione. Mah...
Ed_Bunker
07-07-2004, 19:03
Originariamente inviato da Ed_Bunker
A me non interesserebbe sapere quale specifico pid abbia generato il segnale. Vorrei soltanto avere il modo di
sapere quale funzione il figlio ha portato a termine.
Dovrebbe succedere qualcosa del genere:
...
int med1, med2, med3, med4;
/*Quattro differenti richieste. Per gni richiesta c'e'
una precisa funzione per soddisfarla...*/
/*Il padre riceve una richiesta e la codifica*/
pid = fork();
if (pid==0)/*Processo figlio*/
{
/*Esegue la funzione che il padre ha "deciso" debba essere seguita*/
}
else
{/*Processo padre*/
struct timeval t1, t2;
gettimeofday(&t1, NULL);
/*Va ad aspettare altre richieste ma nel contempo e' pronto a fare la
seconda gettimeofday() quando il figlio avra' terminato di eseguire la
funzione... ma come ?!?*/
....
....
:help: :help: :help: :help: :help:
The wait4() call provides a more general interface for programs that need
to wait for certain child processes, that need resource utilization
statistics accumulated by child processes, or that require options. The
other wait functions are implemented using wait4().
Forse ti puo' servire, sicuramente per le statistiche. Spero solo che quel "require option" possa servirti. :)
UPDATE: Leggo solo adesso...ma non puoi usare socket e far si che ogni richiesta di connessione del figlio faccio forkare un altro processo dal padre che gestisce la connessione mentre il padre originario resta in attesa di altre connessioni?
Detto cosi' suona tremendo...provo a scrivertelo copiandolo da alcune dispense:
while(1) {
clientFd = accept(serverFd, clientSockAddrPtr, &clientLen);
if ( fork() == 0 ) {
VARIEOPERAZ_come_aspettare_che_termini_il_figlio_comunciandoci_anche
close (clientFd);
exit(0);
} else
close(clientFd);
}
Cya!
ilsensine
08-07-2004, 08:51
Originariamente inviato da Ed_Bunker
A me non interesserebbe sapere quale specifico pid abbia generato il segnale. Vorrei soltanto avere il modo di sapere quale funzione il figlio ha portato a termine.
Leggi in /dev/random e azzarda una ipotesi :D
Seriamente, tieniti una lista di strutture che contengono i vari pid creati, la funzione assegnata al pid e l'istante di inizio processamento. Nel sighandler sfogli la lista fino a trovare quella relativa al tuo pid.
Ed_Bunker
08-07-2004, 10:20
Originariamente inviato da Dun
The wait4() call provides a more general interface for programs that need
to wait for certain child processes, that need resource utilization
statistics accumulated by child processes, or that require options. The
other wait functions are implemented using wait4().
Forse ti puo' servire, sicuramente per le statistiche. Spero solo che quel "require option" possa servirti. :)
UPDATE: Leggo solo adesso...ma non puoi usare socket e far si che ogni richiesta di connessione del figlio faccio forkare un altro processo dal padre che gestisce la connessione mentre il padre originario resta in attesa di altre connessioni?
Detto cosi' suona tremendo...provo a scrivertelo copiandolo da alcune dispense:
while(1) {
clientFd = accept(serverFd, clientSockAddrPtr, &clientLen);
if ( fork() == 0 ) {
VARIEOPERAZ_come_aspettare_che_termini_il_figlio_comunciandoci_anche
close (clientFd);
exit(0);
} else
close(clientFd);
}
Cya!
Devo utilizzare "per forza le pipe".
_ Il processo padre riceve una richiesta dalla pipe
_Codifica tale richiesta e si forka per fare in modo che la richiesta venga soddisfatta dal processo figlio
_Il processo padre e' adesso disponibile ad accettare nuove richieste
_Quando CIASCUN figlio termina il processo il padre se ne deve accorgere perche' e' necessario che mantenga aggiornate le medie dei tempi di esecuzione delle funzioni che i figli utilizzano per soddisfare le richieste
Ed_Bunker
08-07-2004, 10:51
Originariamente inviato da ilsensine
Leggi in /dev/random e azzarda una ipotesi :D
Seriamente, tieniti una lista di strutture che
contengono i vari pid creati, la funzione assegnata
al pid e l'istante di inizio processamento.
Nel sighandler sfogli la lista fino a trovare quella
relativa al tuo pid.
Se facessi cosi perderei la "bonta'" della stima della
gettimeofday. No ?!? Dovrei scorrere ogni volta le struct
per controllare quale funzione ha svolto il pid che mi ha
mandato la SIGCHLD.
Penso ci sia qualcosa si piu' semplice...
Potrebbe fare la gettimeofday() il processo figlio e calcolare
esso stesso quanto ci vuole per eseguire la funzione
"indicata" dal processo padre.
E poi, alla terminazione, il processo padre cattura il
SIGCHLD e dovrebbe avere il modo di accedere al
tempo calcolato dalla gettimeofday del figlio. Che
magari gli viene esplicitamente passato dal figlio.
Esempio:
int media1, media2, media3, media4;
int main(int argc, char * argv)
...
...
/*fd = descrittore in lettura della pipe*/
while (true)
{
/*Le letture avvengono mediante la codifica
a lunghezza variabile dei messaggi: invio la lunghezza
del messaggio seguita immediatamente (In una sola write !)
dal messaggio stesso*/
int messLength;
read(fd, &messLength, sizeof(int));
char * mess = (char*) malloc(sizeof(char) * messLength + 1;
read(fd, mess, messLength);
mess[messLength] = '\0';
/*Carattere di terminazione*/
char ** fields = split_arg(mess);
/*I messaggi sono del tipo:
"1 PID" : voglio la lista dei file .txt
"2 PID subString" : voglio che sia cercata
la stringa subString nei file .txt presenti
etc.
etc.
Il primo campo del messaggio e' quello discriminante
per decidere quale funzione debba essere eseguita
*/
int funType = atoi(field[0]);
...
...
if (funType == 2)
{
int pid;
struct sigaction new, old;
new.sa_handler = gest;
sigaction (SIGCHLD, &new, &old);
/*Adesso torno ad aspettare nuove richieste*/
if ((pid = fork()) == 0)/*FIGLIO*/
{
struct timeval start, end;
getimeofday(&start,NULL);
/*Richiama la funzione idonea*/
findString(.../*parametri vari*/...);
gettimeofday(&end, NULL);
long int time =
(end.tv_sec - start.tv_sec) * 1000000 +
(end.tv_usec - start.tv_usec);
exit(2);
/*uscendo esplicitamente con codice 2 potrei indicare
al padre che ho svolto la funzione 2: e' "sbagliato"
fare cosi ?!??*/
}
else/*PADRE*/
{
/*Torno ad attendere nuove richieste*/
}
...
...
}
/*Routine per gestire in SIGCHLD*/
void gestisci(int sig)
{
int status;
wait(&status);
/*Questa mi dovrebbe restituire lo stato con cui e' uscito
il figlio che ha provocato la SIGCHLD. No !?!?*/
...
...
if (status == 2)
{ /*Adesso dovrei poter accedere alla variabile time per
aggiornare la media della funzione corrispondente.
Ma come ?!? E quindi fare...
*/
media2 = @ * media2 + (1 - @) * time;
}
}
Help... :cry: :cry: :cry:
ilsensine
08-07-2004, 11:17
Originariamente inviato da Ed_Bunker
Se facessi cosi perderei la "bonta'" della stima della
gettimeofday. No ?!? Dovrei scorrere ogni volta le struct
per controllare quale funzione ha svolto il pid che mi ha
mandato la SIGCHLD.
Perché perderesti la "bontà della stima"?
_Prima_ esegui la gettimeofday, _poi_ cerchi la struct corrispondente al tuo pid.
Ed_Bunker
08-07-2004, 12:04
Originariamente inviato da ilsensine
Perché perderesti la "bontà della stima"?
_Prima_ esegui la gettimeofday, _poi_ cerchi la struct corrispondente al tuo pid.
Ma come faccio a sapere "su cosa" farla la gettimeofday() ?!
Ovvero: gettimeofday(&end, NULL); /*Dov'e' "end" e' dove trovo "start"*/
Dove la faccio la gettimeofday ? La faccio fare 'completamente' al figlio oppure la 'prima' la fa il processo padre e la 'seconda' la fa la routine di gestione del segnale ? :confused:
ilsensine
08-07-2004, 12:15
Originariamente inviato da Ed_Bunker
La faccio fare 'completamente' al figlio oppure la 'prima' la fa il processo padre e la 'seconda' la fa la routine di gestione del segnale ? :confused:
Puoi elaborare la differenza tra "processo padre" e "routine di gestione del segnale"?
Ed_Bunker
08-07-2004, 13:07
Originariamente inviato da ilsensine
Puoi elaborare la differenza tra "processo padre" e "routine di gestione del segnale"?
Scusami ma non capisco cosa intendi per "differenza tra processo padre e routine di gestione del segnale " ...
ilsensine
08-07-2004, 13:09
Originariamente inviato da Ed_Bunker
Scusami ma non capisco cosa intendi per "differenza tra processo padre e routine di gestione del segnale " ...
Sei tu che hai fatto questa distinsione ;)
Il gestore del segnale _è_ il processo padre. E' lui che deve misurare il tempo, non il child (in quanto non dispone di tecniche veloci per passare il valore al padre).
Non capisco perché ti preoccupa effettuare la seconda gettimeofday nel sighandler...
ilsensine
08-07-2004, 13:11
Cmq ho trovato la soluzione più rapida al tuo problema: vedi man sigaction, nella parte che parla di siginfo_t, in particolare la descrizione dei campi si_utime e si_stime ;)
Ed_Bunker
08-07-2004, 13:19
Originariamente inviato da ilsensine
Sei tu che hai fatto questa distinsione ;)
Il gestore del segnale _è_ il processo padre. E' lui che deve misurare il tempo, non il child (in quanto non dispone di tecniche veloci per passare il valore al padre).
Non capisco perché ti preoccupa effettuare la seconda gettimeofday nel sighandler...
Effettivamente... Faccio la gettimeofday(...) appena fatta la fork e poi faccio la seconda gettimeofday(...) nella routine. Ma l' "idea" di utilizzare lo stato di uscita del figlio per sapere quale media andara ad aggiornare potrebbe andar bene ?
thks
Ed_Bunker
08-07-2004, 13:21
Originariamente inviato da ilsensine
Cmq ho trovato la soluzione più rapida al tuo problema: vedi man sigaction, nella parte che parla di siginfo_t, in particolare la descrizione dei campi si_utime e si_stime ;)
Ok... Ora vado in facolta'... Daro' un'occhiata nel pomeriggio...
;)
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.