/* soluzione parte C esame del 11 Luglio 2018 */ #include #include #include #include #include #include #include #include typedef int pipe_t[2]; /* tipo di dato per contenere i file descriptors di una pipe */ /* VARIABILI GLOBALI */ int *finito; /* array dinamico per indicare i figli che sono terminati */ /* la semantica di questo array e' che ogni elemento vale 0 se il corrispondente processo NON e' finito, altrimenti vale 1 */ int N; /* numero di processi figli */ int finitof() { /* questa funzione verifica i valori memorizzati nell'array finito: appena trova un elemento uguale a 0 vuole dire che non tutti i processi figli sono finiti e quindi torna 0; tornera' 1 se e solo se tutti gli elementi dell'array sono a 1 e quindi tutti i processi sono finiti */ int i; for (i=0; i < N; i++) if (!finito[i]) /* appena ne trova uno che non ha finito */ return 0; /* ritorna falso */ return 1; } int main(int argc, char **argv) { int pid; /* variabile per fork */ pipe_t *pipe_fp; /* array di pipe per la comunicazione figli-padre*/ pipe_t *pipe_pf; /* array di pipe per l'indicazione padre-figli */ char CZ; /* carattere da cercare */ int fd; /* variabile per open */ char ch; /* variabile per leggere dai file */ char chControllo; /* variabile per inviare indicazione ai figli */ long int posizione; /* QUESTA VARIABILE TIENE TRACCIA DELLA POSIZIONE NEL FILE, SENZA USARE LSEEK. La posizione del primo carattere e' assunta uguale a 0 */ long int posizioneMax; /* usata dal padre per calcolare il massimo */ int indice; /* usata dal padre per tenere traccia dell'indice del figlio che ha calcolato il massimo */ int occorrenze; /* numero di occorrenze trovate che va ritornato al padre */ int status, pidFiglio, ritorno; /* per wait */ int i, j; /* indici per cicli */ int nr, nw; /* per controlli read e write su/da pipe */ if (argc < 4) { printf("Errore numero parametri, dato che argc=%d\n", argc); exit(1); } /* Controlliamo se il primo parametro e' un singolo carattere */ if (strlen(argv[1]) != 1) { printf("Errore primo parametro non singolo carattere %s\n", argv[1]); exit(2); } CZ = argv[1][0]; /* isoliamo il carattere che devono cercare i figli */ printf("DEBUG-Carattere da cercare %c\n", CZ); N = argc - 2; /* ogni figlio e' associato a argv[2], argv[3]...argv[argc-1] */ /* allocazione memoria dinamica per finito */ finito = (int *) malloc(sizeof(int) * N); if(finito == NULL) { printf("Errore nella allocazione della memoria per array finito\n"); exit(3); } /* ... e inizializzazione a 0: all'inizio nessun figlio e' finito */ memset(finito, 0, N*sizeof(int)); /* allocazione memoria dinamica per pipe_fp e pipe_pf */ pipe_fp=malloc(N*sizeof(pipe_t)); pipe_pf=malloc(N*sizeof(pipe_t)); if ((pipe_fp == NULL) || (pipe_pf == NULL)) { printf("Errore nelle malloc\n"); exit(4); } /* creazione delle pipe */ for (i=0; i < N; i++) { if (pipe(pipe_fp[i])!=0) { printf("Errore creazione delle pipe figli-padre\n"); exit(5); } if (pipe(pipe_pf[i])!=0) { printf("Errore creazione delle pipe padre-figli\n"); exit(6); } } printf("DEBUG-Sono il processo padre con pid %d e sto per generare %d figli\n", getpid(), N); /* creazione dei processi figli */ for (i=0; i < N; i++) { if ((pid=fork()) < 0) /* errore */ { printf("Errore nella fork con indice %d\n", i); exit(7); } if (pid == 0) { /* codice del figlio */ /* stampa di debugging */ printf("DEBUG-Figlio di indice %d e pid %d associato al file %s\n",i,getpid(), argv[i+2]); /* chiudiamo le pipe che non servono */ /* ogni figlio scrive solo su pipe_fp[i] e legge solo da pipe_pf[i] */ for (j=0;j posizioneMax) { /* dobbiamo aggiornare il massimo */ posizioneMax = posizione; /* debbiamo tenere conto dell'indice del processo che ha inviato il massimo */ indice = i; } } } /* bisogna mandare ai figli l'indicazione giusta (S per scrivere, N per NON scrivere) */ /* OSSERVAZIONE IMPORTANTE: IN QUESTA SOLUZIONE NON BASTA LA VARIABILE FINITO DATO CHE LA FASE DI SCRITTURA DEL PADRE AI FIGLI VIENE FATTA NEL CICLO FOR CHE SEGUE E QUINDI IL PADRE DEVE AVERE MODO DI FARE LA SCRITTURA SE E SOLO SE IL FIGLIO GLI HA INVIATO QUALCOSA E QUINDI NON E' FINITO, ALTRIMENTI (IN CASO DI ASSENZA DI QUESTO CONTROLLO) SE UN FIGLIO E' FINITO E IL PADRE GLI MANDA COMUNQUE IL CARATTERE DI CONTROLLO, IL PADRE RICEVEREBBE UN SEGNALE SIGPIPE E MORIREBBE (A MENO CHIARAMENTE DI NON GESTIRE QUESTO SEGNALE CON UNA FUNZIONE HANDLER SPECIFICA)! */ for (i=0; i < N; i++) { if (i == indice) /* figlio che deve scrivere */ chControllo = 'S'; else chControllo = 'N'; if (!finito[i]) { nw=write(pipe_pf[i][1], &chControllo, 1); if (nw != 1) printf("PADRE non e' riuscito ad inviare nulla al figlio di indice %d \n", i); } } } /* Attesa della terminazione dei figli */ for(i=0;i> 8) & 0xFF); printf("Il figlio con pid=%d ha ritornato %d (se 255 errore)\n", pidFiglio, ritorno); } } exit(0); }/* fine del main */