Vladpepe

Untitled

May 23rd, 2019
50
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 9.00 KB | None | 0 0
  1. La parte in C accetta un numero variabile di parametri che rappresentano N nomi di file F1..FN: tutti i file Fi hanno uguale
  2. lunghezza in byte e contengono solo caratteri numerici (queste due proprietà sono garantite dalla parte shell e non devono
  3. essere controllate).
  4. Il processo padre deve generare N processi figli (P0 … PN-1): ogni processo figlio è associato ad uno dei file Fi. Ognuno
  5. di tali processi figli esegue concorrentemente, legge tutti i caratteri del file associato Fi e calcola per ogni carattere
  6. numerico letto il numero intero positivo corrispondente. I processi figli e il processo padre devono attenersi ad uno schema
  7. di comunicazione a pipeline; il figlio PN-1 comunica con il figlio PN-2 etc. fino al figlio P0 che comunica con il padre;
  8. questo schema a pipeline deve essere ripetuto per ogni carattere di ogni file e deve prevedere l’invio indietro, per ogni
  9. carattere, via via di una struttura Si che deve contenere due campi, c1 e c2, con c1 uguale al PID di un figlio e con c2
  10. uguale ad un numero intero positivo. In particolare, l’ultimo processo PN-1 per ogni carattere numerico letto dopo aver
  11. calcolato il numero corrispondente (NumeroN-1), passa indietro (cioè comunica) una struttura SN-1 con il proprio PID e
  12. NumeroN-1; il processo precedente PN-2, dopo aver calcolato il numero (NumeroN-2) corrispondente al carattere numerico
  13. corrente, riceve da PN-1 l'informazione comunicata e passa al processo PN-3 l'informazione ricevuta da PN-1 se NumeroN1 è maggiore o uguale di NumeroN-2 oppure la propria informazione e così via fino a che il primo processo P0, dopo aver
  14. calcolato il numero (Numero0) corrispondente al carattere numerico corrente, riceve da P1 l'informazione comunicata e
  15. passa al processo padre l'informazione ricevuta da P1 se Numero1 è maggiore o uguale di Numero0 oppure la propria
  16. informazione. Quindi, al processo padre devono arrivare tante strutture quanti sono i caratteri numerici dei file letti dai
  17. processi P0, P1, … PN-1. Il padre ha il compito di stampare su standard output tutte le informazioni ricevute dal processo
  18. P0, che rappresentano il numero corrispondente con massimo valore e il PID del processo che lo ha calcolato per ognuno
  19. dei caratteri numerici presenti nei file letti.
  20. Al termine, ogni processo figlio Pi deve ritornare al padre l’ultimo carattere numerico letto dal proprio file associato Fi e il
  21. padre deve stampare su standard output i PID e i valori ritornati dai figli.
  22.  
  23. /* Soluzione parte C:
  24. per la sincronizzazione dei figli occorre creare uno schema di pipe, ossia una pipe che colleghi ogni figlio a quello precedente e successivo. Si noti che il primo processo figlio ha la pipe collegata al padre, e che l'ultimo processo figlio parte in maniera indipendente.
  25. Si scrivera' sempre sulla pipe i e si leggera' da quello (i+1):
  26. figlio N-1  == pipe N-1 ==>   figlio N-2  == pipe N-2 ==> ...
  27.                                    figlio i == pipe i ==>
  28. in particolare il primo figlio e' collegato al padre tramite la pipe 0 */
  29.  
  30. #include <unistd.h>
  31. #include <stdlib.h>
  32. #include <fcntl.h>
  33. #include <sys/wait.h>
  34. #include <stdio.h>
  35. #include <string.h>
  36.  
  37. /* definisco un tipo per un array di due interi */
  38. typedef int pipe_t[2];       
  39.  
  40. /* definizione di una struttura dati che racchiuda il numero corrispondente al carattere numerico e il PID del processo figlio corrente. Questa struttura verra' passata tramite le pipe da un figlio all'altro. */
  41. typedef struct {
  42.     int PID;    /* ha il significato del campo c1 del testo */
  43.     int numero; /* ha il significato del campo c2 del testo */
  44.         } s_num;
  45.  
  46. /* Inizio del programma vero e proprio */
  47. int main(int argc, char **argv) {
  48. int N;      /* Numero di processi figli da creare */
  49. int i;      /* Contatore per la generazione delle pipe/figli*/
  50. int j;      /* Contatore per la chiusura dei lati non usati delle pipe */
  51. pipe_t *p;  /* Array di pipe usate a pipeline da ultimo figlio, al penultimo figlio .... primo figlio e poi a padre: ogni processo (a parte il primo) legge dalla pipe i+1 e scrive sulla pipe i */
  52. char ch;    /* carattere utilizzato nella read del file*/
  53. int status;     /* utilizzato come status di ritorno dei figli*/
  54. int fd;     /* file descriptor generico */
  55. int pid;        /* valore di ritorno della fork o pid del processo corrente */
  56. s_num cur_num;  /* struttura che ogni figlio deve usare */
  57. s_num pipe_num; /* struttura che verra' letta dalla pipe */
  58. char ritorno;   /* variabile per valore di ritorno per maggiore chiarezza, anche se in questo caso non serviva */
  59.  
  60. /* controllo sul numero dei parametri: non richiesto ma non ha senso se non abbiamo almeno due file e quindi almeno tre argomenti (argv[0] compreso) */
  61. if (argc < 3)
  62. {   printf("Uso: %s num variabile di file, almeno 2\n", argv[0]);
  63.     exit(1);
  64. }
  65.  
  66. /* il numero di figli da generare e' pari al numero di file passati come argomento, quindi argc-1 */
  67. N = argc-1;
  68.  
  69. /* allocazione delle pipe: occorre un numero di pipe pari al numero di figli (una viene usata per la comunicazione con il padre) */    
  70. p = (pipe_t *)malloc(sizeof(pipe_t)*N);  
  71. if ( p == NULL )
  72. {
  73.     printf("Impossibile allocare il vettore di pipe\n");
  74.     exit(2);
  75. }
  76.  
  77. for (i=0; i<N; i++)
  78. {
  79.     if (pipe(p[i]) != 0)
  80.     {
  81.         printf("Errore nella creazione della pipe %d\n", i);
  82.         exit(3);
  83.     }
  84. }
  85.  
  86. /* creazione degli N figli. Dove la fork ritorna 0 significa che sono nel codice del figlio, altrimenti nel padre o in errore se ho -1 */
  87. for (i=0; i<N; i++)  /* ATTENZIONE LA CREAZIONE VIENE FATTA NEL SOLITO MODO DATO CHE LA SOLUZIONE DEVE CONSIDERARE CHE LA PIPELINE PARTE DALL'ULTIMO PROCESSO CREATO, IN TERMINI TEMPORALI */
  88. {
  89.     pid = fork();
  90.     /* controllo del valore di ritorno della fork */
  91.     if (pid == -1)
  92.     {
  93.         printf("Errore nella fork %d-esima\n",i);
  94.         exit(4);
  95.     }
  96.     else
  97.     if (pid == 0)
  98.     {
  99.     /* CODICE DEL FIGLIO */
  100.         printf("Sono il figlio %d e sono associato al file %s\n", getpid(), argv[i+1]);
  101.     /* anzitutto chiudo i lati della pipe che non uso con questo figlio. Chiudo in scrittura tutte le pipe eccetto la i, chiudo in lettura tutte le pipe eccetto i+1 */
  102.     /* chiudo tutte le pipe non usate */  
  103.         for (j=0; j<N; j++)
  104.         {
  105.             if ( j!=i && j!=(i+1))
  106.             {
  107.                 close(p[j][0]);     /* lato lettura */
  108.                 close(p[j][1]);     /* lato scrittura */
  109.             }
  110.         }
  111.     /* non devo leggere dalla pipe i-esima */
  112.         close(p[i][0]);
  113.         /* non devo scrivere sulla pipe i+1: usiamo l'operatore % con valore N in modo che per il figlio N-1esimo si vada a chiudere il lato scrittura della pipe p[0]  */
  114.                 close(p[(i+1)%N][1]);
  115.  
  116.     /* apro il file i-esimo e leggo un carattere numerico alla volta e lo converto */
  117.         fd = open(argv[i+1], O_RDONLY);  
  118.         if (fd < 0)
  119.         {  
  120.             printf("Errore nell'apertura del file %s\n", argv[i+1]);
  121.             exit(-1); /* decidiamo di tornare -1 che verra' interpretatto dal padre come 255 che non e' un valore accettabile per il padre */
  122.         }
  123.         while (read(fd,&ch,1))
  124.         {
  125.         /* inizializzo la mia struttura dati: ATTENZIONE farlo dentro al while dato che puo' essere modificata */
  126.             cur_num.PID = getpid();
  127.             cur_num.numero=(int) (ch - '0');
  128.             /*
  129.             printf("ho letto numero=%d e pid=%d\n", cur_num.numero, cur_num.PID);
  130.             */
  131.             /* ora posso comunicare al figlio precedente la mia informazione. ATTENZIONE: il figlio N-1esimo non deve leggere da nessuna pipe, ma gli altri figli devono prima confrontare la loro informazione con quella ricevuta sulla pipe */
  132.             if (i != N-1)
  133.             {
  134.                 /* se non sono l'ultimo processo, resto bloccato sulla read fino a quando non mi viene passato un qualche dato */
  135.                 read(p[i+1][0],&pipe_num,sizeof(s_num));
  136.                 /*
  137.                 printf("ho ricevuto numero=%d e pid=%d\n", pipe_num.numero, pipe_num.PID);
  138.                 */
  139.                 /* confronto i dati ricevuti */
  140.                 if (pipe_num.numero >= cur_num.numero)
  141.                 {
  142.                     cur_num.numero = pipe_num.numero;
  143.                     cur_num.PID = pipe_num.PID;
  144.                 }  
  145.             }  
  146.             /* invio i dati */
  147.             /*
  148.             printf("sto per inviare numero=%d e pid=%d\n", cur_num.numero, cur_num.PID);
  149.             */
  150.             write(p[i][1],&cur_num,sizeof(s_num));
  151.         }  
  152.  
  153.         /* salvo il valore di ritorno anche se non serve, per maggiore leggibilita' */
  154.         ritorno =  ch;
  155.         /* termino il processo ritornando l'ultimo carattere (che e' sicuramente minore di 255) */
  156.         exit(ritorno);
  157.     }   /* FINE CODICE DEL FIGLIO */
  158. }   /* fine del ciclo for */
  159.  
  160. /* CODICE DEL PADRE */
  161. /* chiudo tutte le pipe non usate */  
  162. for (j=0;j<N;j++)  
  163. {
  164.     if( j != 0 )
  165.         /* non devo chiudere la pipe lettura dell'ultimo figlio */          
  166.         close (p[j][0]);
  167.     close (p[j][1]);
  168. }
  169.  
  170. /* leggo i valori passati dal primo figlio fino a che ce ne sono */
  171. while (read(p[0][0],&cur_num,sizeof(s_num)))
  172. {
  173.     printf("Numero calcolato: %d dal figlio pid=%d\n",cur_num.numero, cur_num.PID);    
  174. }
  175.  
  176. /* Attesa della terminazione dei figli */
  177. for (i=0;i<N;i++)
  178. {
  179.     pid = wait(&status);
  180.     if (pid < 0)
  181.         printf("Errore in wait\n");
  182.     else
  183.     {
  184.         if(WIFEXITED(status)) /* se il figlio e` uscito normalmente... */
  185.             printf("Figlio pid: %d terminato con exit: %c\n", pid, WEXITSTATUS(status));
  186.         else
  187.             printf("Figlio con pid: %d terminato in modo anomalo\n", pid);
  188.     }
  189.        
  190. }
  191. exit(0);
  192. }   /* fine del main */
Add Comment
Please, Sign In to add comment