Advertisement
Vladpepe

Untitled

May 23rd, 2019
127
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 9.39 KB | None | 0 0
  1. La parte in C accetta un numero variabile N+1 di parametri (con N maggiore o uguale a 2) che
  2. rappresentano N+1 nomi di file (F1, F2,... FN e AF) con uguale lunghezza in byte (che viene
  3. assicurata dalla parte shell e non si deve controllare).
  4. Il processo padre è associato al file AF e deve generare N processi figli (P0 … PN-1) ognuno dei
  5. quali è associato ad uno dei file Fi. Ogni processo figlio Pi deve leggere i caratteri del file
  6. associato Fi sempre fino alla fine solo dopo aver ricevuto l’indicazione dal padre di procedere.
  7. Infatti, i processi figli devono attenersi a questo schema di comunicazione/sincronizzazione con il
  8. padre: il figlio P0, ricevuta l’indicazione dal padre che può procedere, legge il primo carattere e lo
  9. comunica al padre che lo confronta con il primo carattere del file AF; il figlio P1, ricevuta
  10. l’indicazione dal padre che può procedere, legge il primo carattere e lo comunica al padre che lo
  11. confronta con il primo carattere del file AF etc. fino al figlio PN-1, ricevuta l’indicazione dal padre
  12. che può procedere, legge il primo carattere e lo comunica al padre che lo confronta con il primo
  13. carattere del file AF; questo schema deve continuare per gli altri caratteri solo se il confronto ha
  14. successo (cioè i due caratteri sono uguali); se un confronto non ha successo, il padre non deve
  15. inviare al corrispondente figlio l’indicazione di procedere. Una volta che il padre termina la lettura
  16. del file associato AF, deve terminare forzatamente (con un apposito segnale) i figli per i quali il
  17. confronto non abbia avuto successo.
  18. Al termine, i processi figli Pi che non sono stati terminati forzatamente devono ritornare al padre
  19. l’indicazione di successo secondo la semantica di UNIX; il padre deve stampare su standard output
  20. il PID di ogni figlio con l’indicazione di terminazione anormale o normale e in questo caso il valore
  21. ritornato dal figlio insieme con il nome del file il cui contenuto risulta uguale a quello del file AF.
  22. /* versione con N pipe di comunicazione/sincronizzazione fra padre e figli  e altre N di comunicazione fra figli e padre; inoltre uso del segnale SIGKILL */
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <unistd.h>
  26. #include <sys/wait.h>
  27. #include <sys/types.h>
  28. #include <signal.h>
  29. #include <string.h>
  30. #include <fcntl.h>
  31.  
  32. #define PERM 0644
  33.  
  34. typedef int pipe_t[2];
  35.  
  36. int main (int argc, char **argv)
  37. {
  38. int N;              /* numero di file */
  39. int *pid;           /* array di pid per fork */
  40. int *confronto;         /* array di interi per sapere se si deve ancora mandare indicazione di leggere al figlio corrispondente */
  41. pipe_t *pipeFiglioPadre;    /* array di pipe di comunicazione fra figli e padre */
  42. pipe_t *pipePadreFiglio;    /* array di pipe di comunicazione/sincronizzazione fra padre e figlio */
  43. int i,j;            /* contatori */
  44. int fd;             /* file descriptor */
  45. int pidFiglio, status, ritorno; /* per valore di ritorno figli */
  46. char c,ch;          /* carattere per leggere dal file */
  47. char token='v';         /* carattere che serve per sincronizzare i figli: 'v' vai, 't' termina */
  48.  
  49. /* ci vogliono almeno due file trovati che insieme con AF fa un totale di almeno 3 parametri */
  50. if (argc < 4)
  51. {
  52. printf("Errore numero di parametri\n");
  53. exit(1);
  54. }
  55.  
  56. N = argc-2; /* calcoliamo il numero di file trovati */
  57. printf("Numero di processi da creare %d\n", N);
  58.  
  59. /* allocazione pid */
  60. if ((pid=(int *)malloc(N*sizeof(int))) == NULL)
  61. {
  62.         printf("Errore allocazione pid\n");
  63.         exit(2);
  64. }
  65.  
  66. /* allocazione confronto */
  67. if ((confronto=(int *)malloc(N*sizeof(int))) == NULL)
  68. {
  69.         printf("Errore allocazione confronto\n");
  70.         exit(3);
  71. }
  72.  
  73. /* inizializzazione di confronto */
  74. for (i=0;i<N;i++)
  75.     confronto[i]=1;
  76.  
  77. /* allocazione pipe figli-padre */
  78. if ((pipeFiglioPadre=(pipe_t *)malloc(N*sizeof(pipe_t))) == NULL)
  79. {
  80.     printf("Errore allocazione pipe padre\n");
  81.     exit(4);
  82. }
  83.  
  84. /* allocazione pipe padre-figli */
  85. if ((pipePadreFiglio=(pipe_t *)malloc(N*sizeof(pipe_t))) == NULL)
  86. {
  87.     printf("Errore allocazione pipe padre\n");
  88.     exit(5);
  89. }
  90.  
  91. /* creazione pipe */
  92. for (i=0;i<N;i++)
  93.     if(pipe(pipeFiglioPadre[i])<0)
  94.     {
  95.         printf("Errore creazione pipe\n");
  96.         exit(6);
  97.     }
  98.  
  99. /* creazione di altre N pipe di comunicazione/sincronizzazione con il padre: N.B. invece di queste N pipe il padre potrebbe usare lo strumento dei segnali */
  100. for (i=0;i<N;i++)
  101.     if(pipe(pipePadreFiglio[i])<0)
  102.     {
  103.         printf("Errore creazione pipe\n");
  104.         exit(7);
  105.     }
  106.  
  107. /* apertura file assegnato al padre */
  108. if ((fd=open(argv[argc-1],O_RDONLY))<0)
  109.         {
  110.         printf("Impossibile aprire il file %s\n", argv[argc-1]);
  111.         exit(8);
  112.         }
  113.  
  114. /* creazione figli con salvataggio dei pid nell'array */
  115. for (i=0;i<N;i++){
  116.     if ((pid[i]=fork())<0)
  117.     {
  118.         printf("Errore creazione figli\n");
  119.         exit(9);
  120.     }
  121.     else if (pid[i]==0)
  122.     { /* codice figlio */
  123.     printf("Sono il figlio %d di indice %d\n", getpid(), i);
  124.     /* chiusura pipes inutilizzate */
  125.     for (j=0;j<N;j++)
  126.     { /* il figlio non legge dai nessuna pipeFiglioPadre e non scrive su nessuna pipePadreFiglio */
  127.         close (pipeFiglioPadre[j][0]);
  128.         close (pipePadreFiglio[j][1]);
  129.         if (j != i)
  130.         { /* inoltre non scrive e non legge se non su/dalle sue pipe */
  131.             close (pipeFiglioPadre[j][1]);
  132.             close (pipePadreFiglio[j][0]);
  133.         }
  134.     }  
  135.     /* apertura file */
  136.     if ((fd=open(argv[i+1],O_RDONLY))<0)
  137.     {
  138.         printf("Impossibile aprire il file %s\n", argv[i+1]);
  139.         exit(-1); /* deciso di tornare -1 che verra' interpretato come 255 e quindi INSUCCESSO */
  140.     }
  141.     /* ciclo di lettura da pipe per ricevere l'indicazione dal padre e quindi lettura dal file */
  142.         while (read(pipePadreFiglio[i][0], &token, 1))
  143.         {
  144.         /* se il token ricevuto e' 't' allora il padre ha terminato la lettura del suo file e quindi anche questo processo che ha sempre avuto successo nei confronti carattere per carattere deve terminare il ciclo */
  145.         if (token == 't') break;
  146.         /* non c'e' bisogno dell'else dato che se il token e' 't' si esce dal ciclo; quindi sicuramente il token e' 'v' cioe' il padre ha indicato di leggere dal file */
  147.                 read(fd,&c,1);
  148.                 /* printf("HO LETTO IL TOKEN per il carattere %c\n", c); */
  149.         /* il carattere letto va mandato al padre per il confronto */
  150.                 write(pipeFiglioPadre[i][1],&c,1);
  151.         }
  152.     printf("STAMPA DI DEBUGGING: Sono il figlio %d di indice %d e ho finito di leggere il file %s\n", getpid(), i, argv[i+1]);
  153.          /* il file e' terminato e quindi si deve ritornare al padre il valore 0 per indicare successo */
  154.         exit(0);
  155.     }
  156. } /* fine for */
  157.  
  158. /* codice del padre */
  159. /* chiusura pipe */
  160. for(i=0;i<N;i++)
  161.     { /* il padre non legge da nessuna pipePadreFiglio e non scrive su nessuna pipeFiglioPadre */
  162.     close (pipePadreFiglio[i][0]);
  163.     close (pipeFiglioPadre[i][1]);
  164.     }
  165.  
  166. /* il padre deve leggere i caratteri dal file assegnato e confrontarli con quelli inviati dai figli: si ricorda che i file hanno tutti la stessa lunghezza dato che questo e' garantito dalla parte shell */
  167. while (read(fd, &ch, 1))
  168.     for(i=0;i<N;i++)
  169.     {
  170.         /* il padre manda l'indicazione di leggere ad ogni figlio per ogni carattere solo se confronto e' ancora 1 */
  171.         if (confronto[i])
  172.         {
  173.             write(pipePadreFiglio[i][1], &token, 1);
  174.             /* il padre riceve il carattere letto dal figlio e lo confronta con il suo */
  175.             read(pipeFiglioPadre[i][0],&c,1);
  176.                 /* printf("SONO IL PADRE: HO LETTO il carattere %c e il figlio %c\n", ch, c);  */
  177.             if (ch != c)
  178.                         {
  179.             /* i caratteri sono diversi e quindi bisogna resettare il valore corrispondente di confronto  */
  180.             /*  printf("SONO IL PADRE: HO LETTO il carattere %c e il figlio %c e quindi mi segno che non devo più mandare indicazione a questo figlio %d\n", ch, c, pid[i]);  */
  181.  
  182.                 confronto[i]=0;
  183.             }  
  184.         }  
  185.     }  
  186. for(i=0;i<N;i++)
  187.     if (!confronto[i])
  188.     {
  189. /* terminiamo forzatamente tutti i figli che hanno fallito il confronto e che sono bloccati sulla read dalla pipe con il padre */
  190.             if (kill(pid[i], SIGKILL) == -1) /* controlliamo che la kill non fallisca a causa della terminazione di uno dei figli, anche se in questo caso non dovremmo avere mai questo caso */
  191.                     printf("Figlio con pid %d non esiste e quindi è già terminaro\n", pid[i]);;
  192.         }
  193.     else
  194.     {
  195. /* per i figli invece per cui il confronto non e' fallito mandiamo una indicazione di uscire dal ciclo, altrimenti rimarrebbero bloccati sulla read e avremmo un deadlock: dato che il figlio aspetterebbe un token dal padre e il padre aspetterebbe che il figlio finisse (con la wait del codice seguente) */
  196.         token='t';
  197.         write(pipePadreFiglio[i][1], &token, 1);
  198.     }
  199.  
  200. /* Il padre aspetta i figli */
  201. for (i=0; i < N; i++)
  202.         {
  203.                 pidFiglio = wait(&status);
  204.                 if (pidFiglio < 0)
  205.                 {
  206.                 printf("Errore in wait\n");
  207.                 exit (11);
  208.                 }
  209.  
  210.         if ((status & 0xFF) != 0)
  211.                     printf("Figlio con pid %d terminato in modo anomalo\n", pidFiglio);
  212.                 else
  213.                 { ritorno=(int)((status >> 8) & 0xFF);
  214.                   printf("Il figlio con pid=%d ha ritornato il valore %d (se 255 problemi)\n", pidFiglio, ritorno);
  215.                   for (j=0; j < N; j++)
  216.             if (pid[j] == pidFiglio) /* se un figlio termina normalmente vuol dire che non e' stato ucciso dal SIGKILL */
  217.             printf("Questo significa che il figlio di indice %d ha verificato che il file %s e' uguale al file %s\n", j, argv[j+1], argv[argc-1]);
  218.         }
  219.        }
  220. return(0);
  221. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement