Mario, ma l'hai letto il suo codice? wait_child() è una funzione che ha definito lui.Mario Vanoni ha scritto:...
Scusa l'intrusione, ma dove trovo una documentazione su wait_child?...
Emanuele
Moderatore: Staff
Mario, ma l'hai letto il suo codice? wait_child() è una funzione che ha definito lui.Mario Vanoni ha scritto:...
Scusa l'intrusione, ma dove trovo una documentazione su wait_child?...
NO, chiedo venia, ma leggendola,spina ha scritto:Mario, ma l'hai letto il suo codice? wait_child() è una funzione che ha definito lui.Mario Vanoni ha scritto:...
Scusa l'intrusione, ma dove trovo una documentazione su wait_child?...
Emanuele
Ma che dici Mario, la funzione fa si che il padre aspetti la terminazione dei figli e stampa in output una stringa che spiega se il figlio è terminato regolarmente. Scema o no la stampa, la wait() andrebbe comunque chiamata IMHO, tra l'altro se guardi il mio codice io ho eliminato il while() più il pause() proprio perchè preferisco aspettare la terminazione dei figli con la wait() per i motivi che ho spiegato in un altro post.Mario Vanoni ha scritto:...
NO, chiedo venia, ma leggendola,
la sua funzione void wait_child() non fa niente oltre ai printf()!
Quindi una NOP instruction inutile.
Codice: Seleziona tutto
...
kill(getppid(), SIGUSR1);
raise(SIGSTOP);
...
Codice: Seleziona tutto
...
kill(child_pid, SIGCONT);
...
Codice: Seleziona tutto
...
6054: mando il segnale 12
6054: aspetto
6052: sveglio il figlio 6054
6053: mando il segnale 10
6052: sveglio il figlio 6053
6053: aspetto
...
Codice: Seleziona tutto
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#define NCHILD 2
void print_usage()
{
printf("Usage: contaCaratteri <c1> <c2> <max> <fileIn> <fileOut>\n");
}
struct child_info
{
int exceeding_lines,
pid,
signal;
char control_character;
};
struct child_info c_info[NCHILD];
int terminated, wake_up;
void f_child(char *, struct child_info *, int);
void sig_handler(int);
int main(int argc, char ** argv)
{
FILE *file;
int i, pid, status, max;
if ( argc != 6 )
{
print_usage();
return -1;
}
max = atoi(argv[3]);
c_info[0].control_character = *(argv[1]);
c_info[1].control_character = *(argv[2]);
/* FIX: l'esistenza del file si fa con la stat() */
if ( (file = fopen(argv[4], "r")) == NULL )
{
printf("Il file in lettura non esiste.\n");
return -1;
}
fclose(file);
c_info[0].signal = SIGUSR1;
c_info[1].signal = SIGUSR2;
for ( i = 0; i < NCHILD; i++ )
if ( (signal(c_info[i].signal, sig_handler)) == SIG_ERR )
{
perror("signal() non riuscita");
return -1;
}
if ( (signal(SIGTERM, sig_handler)) == SIG_ERR )
{
perror("signal() non riuscita");
return -1;
}
for ( i = 0; i < NCHILD; i++ )
if ( (pid = fork()) < 0 )
{
perror("Fork error");
return -1;
}
else
{
if ( pid == 0 )
f_child(argv[4], &c_info[i], max); /* codice per i figli */
else
c_info[i].pid = pid; /* codice per il padre */
}
/* Solo il padre */
while ( terminated != 2 )
pause();
for ( i = 0; i < NCHILD; i++ )
{
pid = wait(&status);
if ( WIFEXITED(status) )
printf("Il processo figlio con pid %d è terminato volontariamente con stato %d\n", pid, WEXITSTATUS(status));
else
if ( WIFSIGNALED(status) )
printf("Il processo figlio con pid %d è terminato involontariamente a causa del segnale %d\n", pid, WTERMSIG(status));
}
/* Scrittura risultato in fileOut */
if ( (file = fopen(argv[5], "w")) == NULL )
{
printf("Errore nell'apertura del file in scrittura.\n");
return -1;
}
for ( i = 0; i < NCHILD; i++ )
if ( fprintf(file, "Il file contiene %d linee con più di %d occorrenze di %c\n", c_info[i].exceeding_lines, max, c_info[i].control_character) < 0 )
printf("Errore in scrittura del file.\n");
fclose(file);
return 0;
}
/* Funzione per i figli */
void f_child(char *path, struct child_info *c_info, int max)
{
FILE *file;
int buff, occurrance, sig_sent, pid;
if ( (signal(SIGCONT, sig_handler)) == SIG_ERR || (signal(SIGALRM, sig_handler)) == SIG_ERR )
{
perror("signal() non riuscita");
exit(-1);
}
if ( (file = fopen(path, "r")) == NULL )
{
kill(getppid(), SIGTERM);
exit(-1);
}
sig_sent = occurrance = 0;
pid = getpid();
while ( (buff = fgetc(file)) != EOF )
if ( buff == '\n' )
{
if ( occurrance > max )
{
wake_up = 0;
printf("%d: mando il segnale %d\n", pid, c_info->signal);
kill(getppid(), c_info->signal);
printf("%d: aspetto\n", pid);
alarm(1);
raise(SIGALRM);
sig_sent++;
}
occurrance = 0;
}
else
if ( buff == c_info->control_character )
++occurrance;
/* FIX: controllare se buff e' veramente EOF o un errore */
fclose(file);
printf("%d: TERMINO. Ho inviato %d segnali\n", pid, sig_sent);
kill(getppid(), SIGTERM);
exit(0);
}
void sig_handler(int signum)
{
int id = -1;
switch ( signum )
{
/* Gestiti dal padre */
case SIGUSR1:
id = 0;
break;
case SIGUSR2:
id = 1 ;
break;
case SIGTERM:
terminated++;
break;
/* Gestiti dai figli */
case SIGCONT:
printf("%d: ricevuto segnale padre\n", getpid());
wake_up = 1;
break;
case SIGALRM:
if ( ! wake_up )
{
printf("%d: aspetto nel sig_handler() \n", getpid());
alarm(1);
raise(SIGALRM);
}
break;
}
if ( id != -1 )
{
c_info[id].exceeding_lines++;
printf("%d: sveglio il figlio %d\n", getpid(), c_info[id].pid);
kill(c_info[id].pid, SIGCONT);
}
return;
}
Grazie Emanuele.Allora Riccardo, ho studiato un po' .
* I segnali POSIX attuali sono detti "affidabili" (reliable). Questo implica semplicemente il fatto che quando un handler è in esecuzione il segnale viene bloccato e quindi successivi segnali rimangono pendenti
* Se vengono spediti 100 segnali dello stesso tipo prima che il processo li gestisce, allora esso ne riceve sempre e solo uno. In altre parole questi segnali (i segnali reliable) non sono accumulabili
* Non c'è un ordine di consegna, NON si fa chi prima arriva meglio alloggia
Quindi il problema nel nostro codice è relativo al fatto che un figlio invia un sacco di segnali mentre il padre ne riceve molti meno. Infatti supponi che in questo momento sia in esecuzione il figlio, se lui riesce a controllare 100 righe prima che venga schedulato e se 80 di queste righe hanno più di N caratteri allora lui invierà 80 segnali al padre, quando questo però viene portato in esecuzione gli verrà segnalata la presenza del segnale, ma di uno solo.
Per superare questi limiti esistono i segnali POSIX real-time. Per questi vale quanto segue:
* Sono accumulabili
* Hanno un ordine di consegna
* Trasportano informazione, laddove generalmente i segnali per loro natura non lo fanno