Lab. di Sistemi Operativi
Esercitazioni proposte per la lezione del 6 maggio 2011
Utilizzando il compilatore gcc in Linux e disponendosi in gruppi di due persone per ogni PC del labora- torio.
1. Utilizzo della funzione write. Creare un sorgente in linguaggio c (es81.c) che riversi su stdout la stringa costante ”Ciao, mondo!”.
2. Modificare es81.c in modo che i caratteri siano scritti su stderr. Verificare il comportamento del programma cos`ı modificato utilizzando la ridirezione della shell.
3. isualizzare la man page di write. Attenzione: esistono differenti man page per write, visualizzare quella nella sezione di nostro interesse (2, syscall).
4. Modificare es81.c in modo che il valore ritornato da write venga reso disponibile come exit value del processo.
5. Modificare es81.c in modo che il file descriptor venga assegnato dal primo argomento della linea di comando, o venga imposto pari a 1 se assente. Cosa avviene se si indica un fd diverso da 1 o 2?
6. Modificare es81.c in modo che la stringa scritta contenga il valore numerico di fd. Utilizzare un array di char e popolarlo con sprintf.
7. Differenze fra printf e write. Modificare es81.c in modo che l’emissione del carattere di fine linea avvenga con quache secondo di ritardo ed osservare il risultato. Provare lo stesso con la printf.
8. (15 minuti) es82.c Creazione di file. Si utilizzi la funzione open() in un sorgente c il cui obiettivo sia quello di creare un file nella directory corrente avente per nome la stringa rappresentata dal primo argomento.
9. Modifichiamo es82.c in modo da recuperare il valore di ritorno della open ed utilizzarlo come file descriptor per una write.
10. Chiusura di un file: la funzione close. Modificare es82.c in modo che il file creato sia chiuso prima della terminazione.
11. (15 minuti) es83.c Utilizzo di un file esistente. Progettare un programma c che apra il file indicato dal primo argomento e sovrascriva i primi 4 caratteri con la stringa ”ciao”
12. Cosa succede se il file vittima `e pi`u lungo di 4 caratteri? E se fosse pi`u corto?
13. Modificare es83.c in modo che il file venga troncato alla dimensione 4.
14. (25 minuti) es84.c Lettura da file. Creare un sorgente c che legga i primi N caratteri (N<100) dal file F con N ed F rispettivamente primo e secondo argomento della command line.
15. (15 minuti) Modificare es84.c in modo che gli N caratteri letti siano copiati nello stesso file a partire dalla posizione K, con K terzo argomento.
16. Utilizzando la funzione fork() creare un nuovo processo (es85.c)
17. Presentare su stdout il valore ritornato dalla fork(). Si utilizzi la coppia snprintf()/write() al posto della semplice printf()
18. Per quale motivo troviamo su stdout due messaggi (con valori differenti)?
19. Verificare il ruolo di padre e figlio visualizzandolo su standard output.
20. La funzione fork() restituisce -1 in caso di errore (e, ovviamente, non genera il nuovo processo). Ag- giungere questa verifica associandola ad un opportuno messaggio d’errore.
21. Sia il processo padre che il processo figlio hanno un proprio exit value. Utilizzare la funzione wait() per recuperare l’exit value del processo figlio.
22. La wait svolge anche un ruolo di sincronizzazione fra processo padre e processo figlio?
23. (25 minuti) es86.c Condivisione di file. Si progetti una applicazione concorrente composta da due processi, padre e figlio, tali che il file rappresentato dal primo argomento sia aperto prima della fork() ed utilizzato in lettura in modo condiviso per contare i caratteri contenuti leggendoli ad uno ad uno.
24. Creare un Makefile per la compilazione di es86.
25. (10 minuti) es87.c Comportamento della printf in applicazioni concorrenti. Creare un sorgente che utilizzi la printf per emettere una stringa priva di fine linea prima della fork().
26. L’esecuzione di es87 riporta la stringa iniziale per due volte su stdout. Proviamo a modificare il sorgente introducendo la write al posto della printf.
27. (15 minuti) es88.c Creazione di pi`u processi. Creare un sorgente che generi un numero di figli uguale al numero passato come primo argomento.
28. (10 minuti) es88.c Modificare es88.c in modo che ogni figlio stampi su stdout il proprio indice.
29. (15 minuti) es88.c Recupero degli exit value dei processi figli: modificare es88.c in modo che il processo padre attenda la terminazione di tutti i processi figli riportando su stdout gli exit value di ogni processo accanto al pid del processo terminato.
30. Un po’ di ordine: modifichiamo es88.c in modo che le operazioni delegate ai processi figli siano incluse in una funzione.
Soluzione
Esercitazioni proposte per la lezione del 6 maggio 2011
Utilizzando il compilatore gcc in Linux e disponendosi in gruppi di due persone per ogni PC del labora- torio.
1. Utilizzo della funzione write. Creare un sorgente in linguaggio c (es81.c) che riversi su stdout la stringa costante ”Ciao, mondo!”.
Soluzione:
/∗ f i l e : e s 8 1 . c
∗ j o b : s c r i t t u r a su s t d o u t con w r i t e
∗/
#include <u n i s t d . h>
i n t main ( i n t a r g c , char ∗∗ a r g v ) { w r i t e ( 1 , ” Ciao , mondo ! \ n” , 1 3 ) ; return ( 0 ) ;
}
2. Modificare es81.c in modo che i caratteri siano scritti su stderr. Verificare il comportamento del programma cos`ı modificato utilizzando la ridirezione della shell.
Soluzione:
/∗ f i l e : e s 8 1 . c
∗ j o b : s c r i t t u r a su s t d o u t con w r i t e
∗/
#include <u n i s t d . h>
i n t main ( i n t a r g c , char ∗∗ a r g v ) { w r i t e ( 2 , ” Ciao , mondo ! \ n” , 1 3 ) ; return ( 0 ) ;
}
/∗ $ . / e s 8 1 > / d e v / n u l l
∗ $ Ciao , mondo !
∗ $ . / e s 8 1 2> / dev / n u l l
∗ $
∗/
3. isualizzare la man page di write. Attenzione: esistono differenti man page per write, visualizzare quella nella sezione di nostro interesse (2, syscall).
Soluzione:
$ man 2 write
4. Modificare es81.c in modo che il valore ritornato da write venga reso disponibile come exit value del processo.
Soluzione:
/∗ f i l e : e s 8 1 . c
∗ j o b : s c r i t t u r a su s t d o u t con w r i t e
∗/
#include <u n i s t d . h>
i n t main ( i n t a r g c , char ∗∗ a r g v ) {
/∗ l ’ e x i t v a l u e d e l p r o c e s s o c o i n c i d e
∗ con i l v a l o r e d i r i t o r n o d e l l a w r i t e
∗ o v v e r o con i l numero d i c a r a t t e r i
∗ e f f e t t i v a m e n t e s c r i t t i . ∗/
return ( w r i t e ( 2 , ” Ciao , mondo ! \ n” , 1 3 ) ) ; }
5. Modificare es81.c in modo che il file descriptor venga assegnato dal primo argomento della linea di comando, o venga imposto pari a 1 se assente. Cosa avviene se si indica un fd diverso da 1 o 2?
Soluzione:
/∗ f i l e : e s 8 1 . c
∗ j o b : s c r i t t u r a su s t d o u t con w r i t e
∗/
#include <u n i s t d . h>
#include < s t d l i b . h>
i n t main ( i n t a r g c , char ∗∗ a r g v ) { i n t f d ;
i f ( a r g c <2) {
/∗ n e s s u n argomento ∗/
f d =1;
} e l s e {
/∗ f d i n a r g v [ 1 ] , numero ∗/
f d=a t o i ( a r g v [ 1 ] ) ; }
return ( w r i t e ( fd , ” Ciao , mondo ! \ n” , 1 3 ) ) ; }
6. Modificare es81.c in modo che la stringa scritta contenga il valore numerico di fd. Utilizzare un array di char e popolarlo con sprintf.
Soluzione:
/∗ f i l e : e s 8 1 . c
∗ j o b : s c r i t t u r a su s t d o u t con w r i t e
∗/
#include <u n i s t d . h>
#include < s t d l i b . h>
#include <s t d i o . h>
#include < s t r i n g . h>
char s t r i n g a [ 2 5 6 ] ;
i n t main ( i n t a r g c , char ∗∗ a r g v ) { i n t f d ;
i f ( a r g c <2) { f d =1;
} e l s e {
f d=a t o i ( a r g v [ 1 ] ) ; }
s n p r i n t f ( s t r i n g a , 2 5 6 , ” f d=%d : Ciao , mondo ! \ n” , f d ) ; return ( w r i t e ( fd , s t r i n g a , s t r l e n ( s t r i n g a ) ) ) ;
}
7. Differenze fra printf e write. Modificare es81.c in modo che l’emissione del carattere di fine linea avvenga con quache secondo di ritardo ed osservare il risultato. Provare lo stesso con la printf.
Soluzione:
/∗ f i l e : e s 8 1 . c
∗ j o b : w r i t e e p r i n t f , un po ’ d i p r o v e
∗/
#include <u n i s t d . h>
#include < s t d l i b . h>
#include <s t d i o . h>
#include < s t r i n g . h>
char s t r i n g a [ 2 5 6 ] ;
i n t main ( i n t a r g c , char ∗∗ a r g v ) { i n t f d ;
i f ( a r g c <2) { f d =1;
} e l s e {
f d=a t o i ( a r g v [ 1 ] ) ; }
/∗ r i m o s s o i l f i n e l i n e a ’ \ n ’ ∗/
s n p r i n t f ( s t r i n g a , 2 5 6 , ” f d=%d : Ciao , mondo ! ” , f d ) ; w r i t e ( fd , s t r i n g a , s t r l e n ( s t r i n g a ) ) ;
s l e e p ( 1 0 ) ; /∗ a t t e n d o 10 s e c o n d i ∗/
w r i t e ( fd , ” \n” , 1 ) ;
s l e e p ( 1 0 ) ; /∗ a t t e n d o 10 s e c o n d i ∗/
/∗ o r a abbiamo v e r i f i c a t o c h e l a w r i t e non ha r i t a r d i ∗/
/∗ vediamo con l a p r i n t f ∗/
w r i t e ( fd , ” i n v o c o l a p r i n t f : ” , 1 8 ) ; p r i n t f ( ” f d=%d : Ciao , mondo ! ” , f d ) ;
s l e e p ( 1 0 ) ; /∗ a t t e n d o a l t r i 10 s e c o n d i ∗/
p r i n t f ( ” \n” ) ; /∗ s o l o ora , dopo i 10 s e c o n d i , l a p r i n t f mostra i l suo e f f e t t o : i c a r a t t e r i d e l l a prima p r i n t f sono s t a t i r i t a r d a t i f i n o a l \n
∗/
return ( 0 ) ; }
8. (15 minuti) es82.c Creazione di file. Si utilizzi la funzione open() in un sorgente c il cui obiettivo sia quello di creare un file nella directory corrente avente per nome la stringa rappresentata dal primo argomento.
Soluzione:
/∗ f i l e : e s 8 2 . c
∗ j o b : open
∗/
#include <u n i s t d . h>
#include < s t d l i b . h>
#include <s y s / t y p e s . h>
#include <s y s / s t a t . h>
#include < f c n t l . h>
i n t main ( i n t a r g c , char ∗∗ a r g v ) {
i f ( a r g c <2) {
/∗ manca i l nome , usciamo ∗/
w r i t e ( 2 , ” I n s e r i r e i l nome d e l f i l e ! \ n” , 2 8 ) ; e x i t ( 1 ) ;
} e l s e {
open ( a r g v [ 1 ] ,O WRONLY| O CREAT | O EXCL, 0 0 6 6 6 ) ; /∗ a t t e n z i o n e : l a c o s t a n t e o t t a l e 0 0 6 6 6 ,
∗ r e l a t i v a a i p e r m e s s i , v i e n e a p p l i c a t a
∗ a l f i l e dopo l a m a s c h e r a t u r a ad o p e r a
∗ d i umask ∗/
}
return ( 0 ) ; }
9. Modifichiamo es82.c in modo da recuperare il valore di ritorno della open ed utilizzarlo come file descriptor per una write.
Soluzione:
/∗ f i l e : e s 8 2 . c
∗ j o b : open
∗/
#include <u n i s t d . h>
#include < s t d l i b . h>
#include <s y s / t y p e s . h>
#include <s y s / s t a t . h>
#include < f c n t l . h>
#include < s t r i n g . h>
#include <s t d i o . h>
char msg [ 2 5 6 ] ;
i n t main ( i n t a r g c , char ∗∗ a r g v ) { i n t f d ;
i f ( a r g c <2) {
/∗ manca i l nome , usciamo ∗/
w r i t e ( 2 , ” I n s e r i r e i l nome d e l f i l e ! \ n” , 2 8 ) ; e x i t ( 1 ) ;
} e l s e {
f d=open ( a r g v [ 1 ] ,O WRONLY| O CREAT | O EXCL, 0 0 6 6 6 ) ; s n p r i n t f ( msg , s i z e o f ( msg ) , ” f d=%d\n” , f d ) ;
w r i t e ( 1 , msg , s t r l e n ( msg ) ) ; }
/∗ u t i l i z z i a m o l a w r i t e su f d : ∗/
return ( w r i t e ( fd , ” Ciao , Mondo ! \ n” , 1 3 ) ) ;
/∗ f d e ’ un nuovo f i l e d e s c r i p t o r c h e puo ’ e s s e r e
∗ u t i l i z z a t o e s a t t a m e n t e come s t d o u t o s t d e r r ∗/
}
10. Chiusura di un file: la funzione close. Modificare es82.c in modo che il file creato sia chiuso prima della terminazione.
Soluzione:
/∗ f i l e : e s 8 2 . c
∗ j o b : open , c l o s e
∗/
#include <u n i s t d . h>
#include < s t d l i b . h>
#include <s y s / t y p e s . h>
#include <s y s / s t a t . h>
#include < f c n t l . h>
#include < s t r i n g . h>
#include <s t d i o . h>
char msg [ 2 5 6 ] ;
i n t main ( i n t a r g c , char ∗∗ a r g v ) { i n t f d ;
i n t nw ; /∗ numero d i c a r a t t e r i s c r i t t i ∗/
i f ( a r g c <2) {
/∗ manca i l nome , usciamo ∗/
w r i t e ( 2 , ” I n s e r i r e i l nome d e l f i l e ! \ n” , 2 8 ) ; e x i t ( 1 ) ;
} e l s e {
f d=open ( a r g v [ 1 ] ,O WRONLY| O CREAT | O EXCL, 0 0 6 6 6 ) ; s n p r i n t f ( msg , s i z e o f ( msg ) , ” f d=%d\n” , f d ) ;
w r i t e ( 1 , msg , s t r l e n ( msg ) ) ; }
nw=w r i t e ( fd , ” Ciao , Mondo ! \ n” , 1 3 ) ; i f ( c l o s e ( f d ) ! = 0 ) {
w r i t e ( 2 , ” E r r o r e i n c h i u s u r a \n” , 2 0 ) ; }
return (nw ) ; }
11. (15 minuti) es83.c Utilizzo di un file esistente. Progettare un programma c che apra il file indicato dal primo argomento e sovrascriva i primi 4 caratteri con la stringa ”ciao”
Soluzione:
/∗ f i l e : e s 8 3 . c
∗ j o b : m o d i f i c a d i f i l e
∗/
#include <u n i s t d . h>
#include < s t d l i b . h>
#include <s y s / t y p e s . h>
#include <s y s / s t a t . h>
#include < f c n t l . h>
#include < s t r i n g . h>
#include <s t d i o . h>
char msg [ 2 5 6 ] ;
i n t main ( i n t a r g c , char ∗∗ a r g v ) { i n t f d ;
i n t nw ; /∗ numero d i c a r a t t e r i s c r i t t i ∗/
i f ( a r g c <2) {
/∗ manca i l nome , usciamo ∗/
w r i t e ( 2 , ” I n s e r i r e i l nome d e l f i l e ! \ n” , 2 8 ) ; e x i t ( 1 ) ;
} e l s e {
f d=open ( a r g v [ 1 ] ,O WRONLY) ;
s n p r i n t f ( msg , s i z e o f ( msg ) , ” f d=%d\n” , f d ) ;
w r i t e ( 1 , msg , s t r l e n ( msg ) ) ; i f ( fd <0) {
s n p r i n t f ( msg , s i z e o f ( msg ) , ” E r r o r e i n a p e r t u r a d i %s ” , a r g v [ 1 ] ) ; w r i t e ( 2 , msg , s t r l e n ( msg ) ) ;
e x i t ( 1 ) ; }
}
nw=w r i t e ( fd , ” c i a o ” , 4 ) ; i f ( c l o s e ( f d ) ! = 0 ) {
w r i t e ( 2 , ” E r r o r e i n c h i u s u r a \n” , 2 0 ) ; }
return (nw ) ; }
12. Cosa succede se il file vittima `e pi`u lungo di 4 caratteri? E se fosse pi`u corto?
Soluzione:
La dimensione finale del file e’ il massimo fra 4 ed il numero di caratteri precedente 13. Modificare es83.c in modo che il file venga troncato alla dimensione 4.
Soluzione:
/∗ f i l e : e s 8 3 . c
∗ j o b : m o d i f i c a d i f i l e
∗/
#include <u n i s t d . h>
#include < s t d l i b . h>
#include <s y s / t y p e s . h>
#include <s y s / s t a t . h>
#include < f c n t l . h>
#include < s t r i n g . h>
#include <s t d i o . h>
char msg [ 2 5 6 ] ;
i n t main ( i n t a r g c , char ∗∗ a r g v ) { i n t f d ;
i n t nw ; /∗ numero d i c a r a t t e r i s c r i t t i ∗/
i f ( a r g c <2) {
/∗ manca i l nome , usciamo ∗/
w r i t e ( 2 , ” I n s e r i r e i l nome d e l f i l e ! \ n” , 2 8 ) ; e x i t ( 1 ) ;
} e l s e {
f d=open ( a r g v [ 1 ] ,O WRONLY) ;
/∗ |O TRUNC a z z e r a l a l u n g h e z z a d e l f i l e a l l ’ a t t o
∗ d e l l a open ∗/
s n p r i n t f ( msg , s i z e o f ( msg ) , ” f d=%d\n” , f d ) ; w r i t e ( 1 , msg , s t r l e n ( msg ) ) ;
i f ( fd <0) {
s n p r i n t f ( msg , s i z e o f ( msg ) ,
” E r r o r e i n a p e r t u r a d i %s ” , a r g v [ 1 ] ) ; w r i t e ( 2 , msg , s t r l e n ( msg ) ) ;
e x i t ( 1 ) ; }
}
nw=w r i t e ( fd , ” c i a o ” , 4 ) ;
f t r u n c a t e ( fd , 4 ) ; /∗ t r o n c a m e n t o manuale ∗/
i f ( c l o s e ( f d ) ! = 0 ) {
w r i t e ( 2 , ” E r r o r e i n c h i u s u r a \n” , 2 0 ) ; }
return (nw ) ; }
14. (25 minuti) es84.c Lettura da file. Creare un sorgente c che legga i primi N caratteri (N<100) dal file F con N ed F rispettivamente primo e secondo argomento della command line.
Soluzione:
/∗ f i l e : e s 8 4 . c
∗ j o b : l e t t u r a d i N c a r a t t e r i da F
∗ uso : e s 8 4 N F
∗/
#include <s t d i o . h>
#include <u n i s t d . h>
#include < s t r i n g . h>
#include < s t d l i b . h>
#include <s y s / t y p e s . h>
#include <s y s / s t a t . h>
#include < f c n t l . h>
char a r r a y [ 1 0 1 ] ; /∗ 100 + ’ \ 0 ’ ∗/
char msg [ 2 5 6 ] ; /∗ m e s s a g g i o ∗/
i n t f d ; /∗ f i l e d e s c r i p t o r ∗/
i n t N; /∗ primo a r g ∗/
char ∗F ; /∗ s e c o n d o a r g ∗/
i n t nr ; /∗ numero c h a r l e t t i ∗/
i n t main ( i n t a r g c , char ∗∗ a r g v ) { switch ( a r g c ) { /∗ num a r g s ∗/
case 3 :
N=a t o i ( a r g v [ 1 ] ) ; F=a r g v [ 2 ] ;
break ; d e f a u l t :
s n p r i n t f ( msg , s i z e o f ( msg ) ,
” uso : %s N F\n” , a r g v [ 0 ] ) ; w r i t e ( 2 , msg , s t r l e n ( msg ) ) ; e x i t ( 1 ) ;
}
f d=open (F ,O RDONLY ) ;
i f ( fd <0) { /∗ c h k open ∗/
s n p r i n t f ( msg , s i z e o f ( msg ) ,
” E r r o r e i n a p e r t u r a \n” ) ; w r i t e ( 2 , msg , s t r l e n ( msg ) ) ; e x i t ( 1 ) ;
}
i f (N>100) { /∗ c h k N ∗/
s n p r i n t f ( msg , s i z e o f ( msg ) ,
”N t r o p p o g r a n d e \n” ) ; w r i t e ( 2 , msg , s t r l e n ( msg ) ) ;
e x i t ( 1 ) ; }
nr=r e a d ( fd , a r r a y ,N ) ;
i f ( nr <0) { /∗ c h k r e a d ∗/
s n p r i n t f ( msg , s i z e o f ( msg ) ,
” E r r o r e i n l e t t u r a \n” ) ; w r i t e ( 2 , msg , s t r l e n ( msg ) ) ; e x i t ( 1 ) ;
}
a r r a y [ nr ]= ’ \0 ’ ; /∗ t e r m i n o l a s t r i n g a ∗/
s n p r i n t f ( msg , s i z e o f ( msg ) ,
” l e t t o : \n%s \ n T o t a l e %d c a r a t t e r i \n” , a r r a y , nr ) ; w r i t e ( 1 , msg , s t r l e n ( msg ) ) ;
return ( 0 ) ; }
15. (15 minuti) Modificare es84.c in modo che gli N caratteri letti siano copiati nello stesso file a partire dalla posizione K, con K terzo argomento.
Soluzione:
/∗ f i l e : e s 8 4 . c
∗ j o b : l e t t u r a d i N c a r a t t e r i da F
∗ e c o p i a i n p o s i z i o n e K
∗ uso : e s 8 4 N F K
∗/
#include <s t d i o . h>
#include <u n i s t d . h>
#include < s t r i n g . h>
#include < s t d l i b . h>
#include <s y s / t y p e s . h>
#include <s y s / s t a t . h>
#include < f c n t l . h>
char a r r a y [ 1 0 1 ] ; /∗ 100 + ’ \ 0 ’ ∗/
char msg [ 2 5 6 ] ; /∗ m e s s a g g i o ∗/
i n t f d r ; /∗ f i l e d e s c r i p t o r , l e t t u r a ∗/
i n t fdw ; /∗ f i l e d e s c r i p t o r , s c r i t t u r a ∗/
i n t N; /∗ primo a r g ∗/
char ∗F ; /∗ s e c o n d o a r g ∗/
i n t K; /∗ t e r z o a r g ∗/
i n t nr ; /∗ numero c h a r l e t t i ∗/
i n t nw ; /∗ numero c h a r s c r i t t i ∗/
i n t main ( i n t a r g c , char ∗∗ a r g v ) { switch ( a r g c ) { /∗ num a r g s ∗/
case 4 :
N=a t o i ( a r g v [ 1 ] ) ; F=a r g v [ 2 ] ;
K=a t o i ( a r g v [ 3 ] ) ; break ;
d e f a u l t :
s n p r i n t f ( msg , s i z e o f ( msg ) ,
” uso : %s N F K\n” , a r g v [ 0 ] ) ; w r i t e ( 2 , msg , s t r l e n ( msg ) ) ;
e x i t ( 1 ) ; }
f d r=open (F ,O RDONLY ) ;
i f ( f d r <0) { /∗ c h k open ∗/
s n p r i n t f ( msg , s i z e o f ( msg ) ,
” E r r o r e i n a p e r t u r a ( rd ) \ n” ) ; w r i t e ( 2 , msg , s t r l e n ( msg ) ) ; e x i t ( 1 ) ;
}
i f (N>100) { /∗ c h k N ∗/
s n p r i n t f ( msg , s i z e o f ( msg ) ,
”N t r o p p o g r a n d e \n” ) ; w r i t e ( 2 , msg , s t r l e n ( msg ) ) ; e x i t ( 1 ) ;
}
nr=r e a d ( f d r , a r r a y ,N ) ; i f ( nr <0) { /∗ c h k r e a d ∗/
s n p r i n t f ( msg , s i z e o f ( msg ) ,
” E r r o r e i n l e t t u r a \n” ) ; w r i t e ( 2 , msg , s t r l e n ( msg ) ) ; e x i t ( 1 ) ;
}
fdw=open (F ,O WRONLY) ;
i f ( fdw <0) { /∗ c h k open ∗/
s n p r i n t f ( msg , s i z e o f ( msg ) ,
” E r r o r e i n a p e r t u r a ( wr ) \ n” ) ; w r i t e ( 2 , msg , s t r l e n ( msg ) ) ; e x i t ( 1 ) ;
}
i f ( l s e e k ( fdw , K, SEEK SET) ! =K) { /∗ r e t v a l=p o s i z i o n e ∗/
s n p r i n t f ( msg , s i z e o f ( msg ) ,
” E r r o r e n e l p o s i z i o n a m e n t o \n” ) ; w r i t e ( 2 , msg , s t r l e n ( msg ) ) ;
e x i t ( 1 ) ; }
nw=w r i t e ( fdw , a r r a y , nr ) ; s n p r i n t f ( msg , s i z e o f ( msg ) ,
” L e t t i %d c a r a t t e r i \n”
” C o p i a t i %d c a r a t t e r i a l l a p o s i z i o n e %d\n” , nr , nw ,K ) ;
w r i t e ( 1 , msg , s t r l e n ( msg ) ) ; return ( 0 ) ;
}
16. Utilizzando la funzione fork() creare un nuovo processo (es85.c) Soluzione:
/∗ f i l e : e s 8 5 . c
∗ j o b : uso d e l l a f o r k
∗/
#include <s y s / t y p e s . h>
#include <u n i s t d . h>
i n t main ( i n t a r g c , char ∗∗ a r g v ) {
f o r k ( ) ; return ( 0 ) ; }
17. Presentare su stdout il valore ritornato dalla fork(). Si utilizzi la coppia snprintf()/write() al posto della semplice printf()
Soluzione:
/∗ f i l e : e s 8 5 . c
∗ j o b : uso d e l l a f o r k
∗/
#include <s y s / t y p e s . h>
#include <u n i s t d . h>
#include <s t d i o . h>
#include <u n i s t d . h>
#include < s t r i n g . h>
char msg [ 2 5 6 ] ;
i n t main ( i n t a r g c , char ∗∗ a r g v ) {
p i d t f r ; /∗ f o r k r e t u r n v a l u e ∗/
f r=f o r k ( ) ;
s n p r i n t f ( msg , s i z e o f ( msg ) ,
” f o r k : %d\n” , f r ) ; w r i t e ( 1 , msg , s t r l e n ( msg ) ) ; return ( 0 ) ;
}
18. Per quale motivo troviamo su stdout due messaggi (con valori differenti)?
Soluzione:
La funzione fork() invoca la system call omonima che provoca la creazione di un nuovo processo ’clonando’ quello corrente.
Il processo ’originale’, detto padre, ottiene dalla fork un numero intero strettamente positivo che rappresenta il pid del nuovo processo creato
Il nuovo processo, detto ’figlio’, si trova con una copia esatta del processo padre e, quindi, iniziera’ la sua esecuzione dall’istruzione (macchina) appena successiva alla chiamata a fork(). Il valore di ritorno recuperato dal figlio, tuttavia, e’ diverso da quello che ha ottenuto il processo padre ed e’ sempre uguale a 0.
Utilizzando questa differenza, sara’ possibile determinare a programma se il codice viene eseguito dal padre o dal figlio operando in modo diverso.
19. Verificare il ruolo di padre e figlio visualizzandolo su standard output.
Soluzione:
/∗ f i l e : e s 8 5 . c
∗ j o b : uso d e l l a f o r k
∗/
#include <s y s / t y p e s . h>
#include <u n i s t d . h>
#include <s t d i o . h>
#include <u n i s t d . h>
#include < s t r i n g . h>
char msg [ 2 5 6 ] ;
i n t main ( i n t a r g c , char ∗∗ a r g v ) {
p i d t f r ; /∗ f o r k r e t u r n v a l u e ∗/
f r=f o r k ( ) ;
i f ( f r ==0) { /∗ f i g l i o ∗/
s n p r i n t f ( msg , s i z e o f ( msg ) , ” F i g l i o \n” ) ; w r i t e ( 1 , msg , s t r l e n ( msg ) ) ;
} e l s e { /∗ p a d r e ∗/
s n p r i n t f ( msg , s i z e o f ( msg ) ,
” Padre d e l f i g l i o %d\n” , f r ) ; w r i t e ( 1 , msg , s t r l e n ( msg ) ) ;
}
return ( 0 ) ; }
20. La funzione fork() restituisce -1 in caso di errore (e, ovviamente, non genera il nuovo processo). Ag- giungere questa verifica associandola ad un opportuno messaggio d’errore.
Soluzione:
/∗ f i l e : e s 8 5 . c
∗ j o b : uso d e l l a f o r k
∗/
#include <s y s / t y p e s . h>
#include <u n i s t d . h>
#include <s t d i o . h>
#include <u n i s t d . h>
#include < s t r i n g . h>
char msg [ 2 5 6 ] ;
i n t main ( i n t a r g c , char ∗∗ a r g v ) {
p i d t f r ; /∗ f o r k r e t u r n v a l u e ∗/
f r=f o r k ( ) ; switch ( f r ) {
case 0 : /∗ f i g l i o ∗/
s n p r i n t f ( msg , s i z e o f ( msg ) , ” F i g l i o \n” ) ; w r i t e ( 1 , msg , s t r l e n ( msg ) ) ;
break ;
case −1: /∗ e r r o r e , n e s s u n nuovo p r o c e s s o ∗/
s n p r i n t f ( msg , s i z e o f ( msg ) , ” E r r o r e i n f o r k \n” ) ; w r i t e ( 1 , msg , s t r l e n ( msg ) ) ;
break ;
d e f a u l t : /∗ p a d r e ∗/
s n p r i n t f ( msg , s i z e o f ( msg ) ,
” Padre d e l f i g l i o %d\n” , f r ) ; w r i t e ( 1 , msg , s t r l e n ( msg ) ) ;
}
return ( 0 ) ; }
21. Sia il processo padre che il processo figlio hanno un proprio exit value. Utilizzare la funzione wait() per recuperare l’exit value del processo figlio.
Soluzione:
/∗ f i l e : e s 8 5 . c
∗ j o b : uso d e l l a f o r k
∗/
#include <s y s / t y p e s . h>
#include <u n i s t d . h>
#include <s t d i o . h>
#include <u n i s t d . h>
#include < s t r i n g . h>
#include <s y s / w a i t . h>
char msg [ 2 5 6 ] ;
i n t main ( i n t a r g c , char ∗∗ a r g v ) {
p i d t f r ; /∗ f o r k r e t u r n v a l u e ∗/
i n t s t ; /∗ s p a z i o p e r l ’ e x i t v a l u e ∗/
f r=f o r k ( ) ; switch ( f r ) {
case 0 : /∗ f i g l i o ∗/
s n p r i n t f ( msg , s i z e o f ( msg ) , ” F i g l i o \n” ) ; w r i t e ( 1 , msg , s t r l e n ( msg ) ) ;
return ( 4 ) ; /∗ e x i t v a l u e d e l f i g l i o ∗/
break ;
case −1: /∗ e r r o r e , n e s s u n nuovo p r o c e s s o ∗/
s n p r i n t f ( msg , s i z e o f ( msg ) , ” E r r o r e i n f o r k \n” ) ; w r i t e ( 1 , msg , s t r l e n ( msg ) ) ;
break ;
d e f a u l t : /∗ p a d r e ∗/
s n p r i n t f ( msg , s i z e o f ( msg ) ,
” Padre d e l f i g l i o %d\n” , f r ) ; w r i t e ( 1 , msg , s t r l e n ( msg ) ) ;
/∗ uso l a w a i t p e r a t t e n d e r e i l p r o c e s s o
∗ f i g l i o e r e c u p e r a r e i l suo e x i t v a l u e ∗/
w a i t (& s t ) ;
s n p r i n t f ( msg , s i z e o f ( msg ) ,
” E x i t v a l u e : %d\n” ,WEXITSTATUS( s t ) ) ; w r i t e ( 1 , msg , s t r l e n ( msg ) ) ;
}
return ( 0 ) ; }
22. La wait svolge anche un ruolo di sincronizzazione fra processo padre e processo figlio?
Soluzione:
Se proviamo ad eseguire diverse volte il programma es85, potremmo notare che la sequenza con la quale vediamo il messaggio "Figlio..."
e quello "Padre..." non e’ ripetitiva. La stampa di "Exit...", al contrario, sara’ sempre successiva a "Figlio..." anche se operate da processi differenti.
Questo e’ dovuto alla presenza della chiamata a wait() che, per recuperare l’exit value del figlio, deve forzare il processo corrente (padre) ad attendere (wait, appunto) la terminazione del processo figlio.
23. (25 minuti) es86.c Condivisione di file. Si progetti una applicazione concorrente composta da due processi, padre e figlio, tali che il file rappresentato dal primo argomento sia aperto prima della fork() ed utilizzato in lettura in modo condiviso per contare i caratteri contenuti leggendoli ad uno ad uno.
Soluzione:
/∗ f i l e : e s 8 6 . c
∗ j o b : f i l e c o n d i v i s o
∗/
#include <s y s / t y p e s . h>
#include <u n i s t d . h>
#include <s t d i o . h>
#include <u n i s t d . h>
#include < s t r i n g . h>
#include <s y s / w a i t . h>
#include <s y s / s t a t . h>
#include < f c n t l . h>
char msg [ 2 5 6 ] ; i n t f d ;
i n t main ( i n t a r g c , char ∗∗ a r g v ) {
p i d t f r ; /∗ f o r k r e t u r n v a l u e ∗/
i n t s t ; /∗ s p a z i o p e r l ’ e x i t v a l u e ∗/
i n t c o u n t ; /∗ c o n t a t o r e d i r e a d ∗/
char ch ; /∗ s p a z i o p e r l a r e a d ∗/
f d=open ( a r g v [ 1 ] , O RDONLY ) ; i f ( fd <0) return ( − 1 ) ; f r=f o r k ( ) ;
switch ( f r ) {
case 0 : /∗ f i g l i o ∗/
f o r ( c o u n t =0; r e a d ( fd ,& ch ,1)==1; c o u n t ++);
s n p r i n t f ( msg , s i z e o f ( msg ) , ” F i g l i o c o n t a %d\n” , c o u n t ) ; w r i t e ( 1 , msg , s t r l e n ( msg ) ) ;
return ( 4 ) ; /∗ e x i t v a l u e d e l f i g l i o ∗/
break ;
case −1: /∗ e r r o r e , n e s s u n nuovo p r o c e s s o ∗/
s n p r i n t f ( msg , s i z e o f ( msg ) , ” E r r o r e i n f o r k \n” ) ; w r i t e ( 1 , msg , s t r l e n ( msg ) ) ;
break ;
d e f a u l t : /∗ p a d r e ∗/
f o r ( c o u n t =0; r e a d ( fd ,& ch ,1)==1; c o u n t ++);
s n p r i n t f ( msg , s i z e o f ( msg ) ,
” Padre d e l f i g l i o %d , c o n t a : %d\n” , f r , c o u n t ) ;
w r i t e ( 1 , msg , s t r l e n ( msg ) ) ;
/∗ uso l a w a i t p e r a t t e n d e r e i l p r o c e s s o
∗ f i g l i o e r e c u p e r a r e i l suo e x i t v a l u e ∗/
w a i t (& s t ) ;
s n p r i n t f ( msg , s i z e o f ( msg ) ,
” E x i t v a l u e : %d\n” ,WEXITSTATUS( s t ) ) ; w r i t e ( 1 , msg , s t r l e n ( msg ) ) ;
}
return ( 0 ) ; }
24. Creare un Makefile per la compilazione di es86.
Soluzione:
#! / b i n /make −f
# f i l e : M a k e f i l e
# f o r m a t o d e l l a r e g o l a = o b i e t t i v o : d i p e n d e n z e e s 8 6 : e s 8 6 . c
g c c −Wall −o e s 8 6 e s 8 6 . c
# R i c o r d a r s i d e l t a b a l l ’ i n i z i o d i o g n i comando
25. (10 minuti) es87.c Comportamento della printf in applicazioni concorrenti. Creare un sorgente che utilizzi la printf per emettere una stringa priva di fine linea prima della fork().
Soluzione:
/∗ f i l e : e s 8 7 . c
∗ j o b : f o r k e p r i n t f , una v e r i f i c a
∗/
#include <s y s / t y p e s . h>
#include <u n i s t d . h>
#include <s t d i o . h>
char s t r i n g a [ 2 5 6 ] ;
i n t main ( i n t a r g c , char ∗∗ a r g v ) {
/∗ s u b i t o una p r i n t f s e n z a \n ∗/
p r i n t f ( ” Prima d e l l a f o r k ( ) : ” ) ; switch ( f o r k ( ) ) {
case 0 : /∗ f i g l i o ∗/
p r i n t f ( ” f i g l i o \n” ) ; return ( 0 ) ;
case −1:
p r i n t f ( ” e r r o r e \n” ) ; return ( 1 ) ;
d e f a u l t :
p r i n t f ( ” p a d r e \n” ) ; return ( 0 ) ;
} }
26. L’esecuzione di es87 riporta la stringa iniziale per due volte su stdout. Proviamo a modificare il sorgente introducendo la write al posto della printf.
Soluzione:
/∗ f i l e : e s 8 7 . c
∗ j o b : f o r k e p r i n t f , una v e r i f i c a
∗/
#include <s y s / t y p e s . h>
#include <u n i s t d . h>
char s t r i n g a [ 2 5 6 ] ;
i n t main ( i n t a r g c , char ∗∗ a r g v ) {
/∗ s u b i t o una p r i n t f s e n z a \n ∗/
w r i t e ( 1 , ” Prima d e l l a f o r k ( ) : ” , 2 0 ) ; switch ( f o r k ( ) ) {
case 0 : /∗ f i g l i o ∗/
w r i t e ( 1 , ” f i g l i o \n” , 7 ) ; return ( 0 ) ;
case −1:
w r i t e ( 1 , ” e r r o r e \n” , 7 ) ;
return ( 1 ) ; d e f a u l t :
w r i t e ( 1 , ” p a d r e \n” , 6 ) ; return ( 0 ) ;
} }
27. (15 minuti) es88.c Creazione di pi`u processi. Creare un sorgente che generi un numero di figli uguale al numero passato come primo argomento.
Soluzione:
/∗ f i l e : e s 8 8 . c
∗ j o b : f o r k ( ) m u l t i p l a
∗/
#include <s y s / t y p e s . h>
#include <u n i s t d . h>
#include < s t d l i b . h>
#include <s t d i o . h>
#include < s t r i n g . h>
char s t r i n g a [ 2 5 6 ] ;
i n t main ( i n t a r g c , char ∗∗ a r g v ) { i n t n f i g l i ; /∗ N ∗/
i n t i n d i c e ; /∗ i n d i c e d i c r e a z i o n e ∗/
i n t p i d ; /∗ p r o c e s s i d e n t i f i e r ∗/
i f ( a r g c <2) {
s n p r i n t f ( s t r i n g a , 2 5 6 , ” Uso : %s N\n” , a r g v [ 0 ] ) ; w r i t e ( 2 , s t r i n g a , s t r l e n ( s t r i n g a ) ) ;
return ( 1 ) ; } e l s e {
n f i g l i =a t o i ( a r g v [ 1 ] ) ; }
f o r ( i n d i c e =0; i n d i c e < n f i g l i ; i n d i c e ++) { p i d=f o r k ( ) ;
switch ( p i d ) {
case 0 : /∗ f i g l i o ∗/
return ( 0 ) ; /∗ t e r m i n a z i o n e ∗/
case −1: /∗ e r r o r e ∗/
s n p r i n t f ( s t r i n g a , 2 5 6 , ” E r r o r e a l l a %d−ma f o r k \n” , i n d i c e ) ; w r i t e ( 2 , s t r i n g a , s t r l e n ( s t r i n g a ) ) ;
return ( 1 ) ; /∗ t e r m i n a z i o n e p a d r e ∗/
d e f a u l t : /∗ padre , c o n t i n u a ∗/
s n p r i n t f ( s t r i n g a , 2 5 6 , ” C r e a t o f i g l i o %d con p i d %d\n” , i n d i c e , p i d ) ;
w r i t e ( 1 , s t r i n g a , s t r l e n ( s t r i n g a ) ) ; }
}
/∗ i l p a d r e a r r i v a q u i dopo l e N c r e a z i o n i ∗/
return ( 0 ) ; }
28. (10 minuti) es88.c Modificare es88.c in modo che ogni figlio stampi su stdout il proprio indice.
Soluzione:
/∗ f i l e : e s 8 8 . c
∗ j o b : f o r k ( ) m u l t i p l a
∗/
#include <s y s / t y p e s . h>
#include <u n i s t d . h>
#include < s t d l i b . h>
#include <s t d i o . h>
#include < s t r i n g . h>
char s t r i n g a [ 2 5 6 ] ;
i n t main ( i n t a r g c , char ∗∗ a r g v ) { i n t n f i g l i ; /∗ N ∗/
i n t i n d i c e ; /∗ i n d i c e d i c r e a z i o n e ∗/
i n t p i d ; /∗ p r o c e s s i d e n t i f i e r ∗/
i f ( a r g c <2) {
s n p r i n t f ( s t r i n g a , 2 5 6 , ” Uso : %s N\n” , a r g v [ 0 ] ) ; w r i t e ( 2 , s t r i n g a , s t r l e n ( s t r i n g a ) ) ;
return ( 1 ) ; } e l s e {
n f i g l i =a t o i ( a r g v [ 1 ] ) ; }
f o r ( i n d i c e =0; i n d i c e < n f i g l i ; i n d i c e ++) { p i d=f o r k ( ) ;
switch ( p i d ) {
case 0 : /∗ f i g l i o ∗/
s n p r i n t f ( s t r i n g a , 2 5 6 , ” F i g l i o con i n d i c e %d\n” , i n d i c e ) ; w r i t e ( 1 , s t r i n g a , s t r l e n ( s t r i n g a ) ) ;
return ( 0 ) ; /∗ t e r m i n a z i o n e ∗/
case −1: /∗ e r r o r e ∗/
s n p r i n t f ( s t r i n g a , 2 5 6 , ” E r r o r e a l l a %d−ma f o r k \n” , i n d i c e ) ; w r i t e ( 2 , s t r i n g a , s t r l e n ( s t r i n g a ) ) ;
return ( 1 ) ; /∗ t e r m i n a z i o n e p a d r e ∗/
d e f a u l t : /∗ padre , c o n t i n u a ∗/
s n p r i n t f ( s t r i n g a , 2 5 6 , ” C r e a t o f i g l i o %d con p i d %d\n” , i n d i c e , p i d ) ;
w r i t e ( 1 , s t r i n g a , s t r l e n ( s t r i n g a ) ) ; }
}
/∗ i l p a d r e a r r i v a q u i dopo l e N c r e a z i o n i ∗/
return ( 0 ) ; }
29. (15 minuti) es88.c Recupero degli exit value dei processi figli: modificare es88.c in modo che il processo padre attenda la terminazione di tutti i processi figli riportando su stdout gli exit value di ogni processo accanto al pid del processo terminato.
Soluzione:
/∗ f i l e : e s 8 8 . c
∗ j o b : f o r k ( ) m u l t i p l a
∗/
#include <s y s / t y p e s . h>
#include <u n i s t d . h>
#include < s t d l i b . h>
#include <s t d i o . h>
#include < s t r i n g . h>
#include <s y s / w a i t . h>
char s t r i n g a [ 2 5 6 ] ;
i n t main ( i n t a r g c , char ∗∗ a r g v ) { i n t n f i g l i ; /∗ N ∗/
i n t i n d i c e ; /∗ i n d i c e d i c r e a z i o n e ∗/
i n t p i d ; /∗ p r o c e s s i d e n t i f i e r ∗/
i n t s t ; /∗ e x i t s t a t u s ∗/
i f ( a r g c <2) {
s n p r i n t f ( s t r i n g a , 2 5 6 , ” Uso : %s N\n” , a r g v [ 0 ] ) ; w r i t e ( 2 , s t r i n g a , s t r l e n ( s t r i n g a ) ) ;
return ( 1 ) ; } e l s e {
n f i g l i =a t o i ( a r g v [ 1 ] ) ; }
f o r ( i n d i c e =0; i n d i c e < n f i g l i ; i n d i c e ++) { p i d=f o r k ( ) ;
switch ( p i d ) {
case 0 : /∗ f i g l i o ∗/
s n p r i n t f ( s t r i n g a , 2 5 6 , ” F i g l i o con i n d i c e %d\n” , i n d i c e ) ; w r i t e ( 1 , s t r i n g a , s t r l e n ( s t r i n g a ) ) ;
return ( 0 ) ; /∗ t e r m i n a z i o n e ∗/
case −1: /∗ e r r o r e ∗/
s n p r i n t f ( s t r i n g a , 2 5 6 , ” E r r o r e a l l a %d−ma f o r k \n” , i n d i c e ) ; w r i t e ( 2 , s t r i n g a , s t r l e n ( s t r i n g a ) ) ;
return ( 1 ) ; /∗ t e r m i n a z i o n e p a d r e ∗/
d e f a u l t : /∗ padre , c o n t i n u a ∗/
s n p r i n t f ( s t r i n g a , 2 5 6 , ” C r e a t o f i g l i o %d con p i d %d\n” , i n d i c e , p i d ) ;
w r i t e ( 1 , s t r i n g a , s t r l e n ( s t r i n g a ) ) ; }
}
/∗ i l p a d r e a r r i v a q u i dopo l e N c r e a z i o n i ∗/
f o r ( i n d i c e =0; i n d i c e < n f i g l i ; i n d i c e ++) {
/∗ l ’ o r d i n e i n c u i i f i g l i t e r m i n a n o NON e ’ p r e v e d i b i l e ,
∗ q u i n d i i l v a l o r e r e c u p e r a t o a l l a i −esima i t e r a z i o n e
∗ non n e c e s s a r i a m e n t e s i r i f e r i s c e a l l ’ i −esimo
∗ f i g l i o . ∗/
p i d=w a i t (& s t ) ;
s n p r i n t f ( s t r i n g a , 2 5 6 , ” I l f i g l i o con p i d %d r i t o r n a %d\n” , pid ,WEXITSTATUS( s t ) ) ;
w r i t e ( 1 , s t r i n g a , s t r l e n ( s t r i n g a ) ) ; }
return ( 0 ) ; }
30. Un po’ di ordine: modifichiamo es88.c in modo che le operazioni delegate ai processi figli siano incluse in una funzione.
Soluzione:
/∗ f i l e : e s 8 8 . c
∗ j o b : f o r k ( ) m u l t i p l a
∗/
#include <s y s / t y p e s . h>
#include <u n i s t d . h>
#include < s t d l i b . h>
#include <s t d i o . h>
#include < s t r i n g . h>
#include <s y s / w a i t . h>
char s t r i n g a [ 2 5 6 ] ;
/∗ P r o t o t i p o d e l l a f u n z i o n e f i g l i o ∗/
i n t f i g l i o ( i n t argomento ) ;
i n t main ( i n t a r g c , char ∗∗ a r g v ) { i n t n f i g l i ; /∗ N ∗/
i n t i n d i c e ; /∗ i n d i c e d i c r e a z i o n e ∗/
i n t p i d ; /∗ p r o c e s s i d e n t i f i e r ∗/
i n t s t ; /∗ e x i t s t a t u s ∗/
i f ( a r g c <2) {
s n p r i n t f ( s t r i n g a , 2 5 6 , ” Uso : %s N\n” , a r g v [ 0 ] ) ; w r i t e ( 2 , s t r i n g a , s t r l e n ( s t r i n g a ) ) ;
return ( 1 ) ; } e l s e {
n f i g l i =a t o i ( a r g v [ 1 ] ) ; }
f o r ( i n d i c e =0; i n d i c e < n f i g l i ; i n d i c e ++) { p i d=f o r k ( ) ;
switch ( p i d ) {
case 0 : /∗ f i g l i o ∗/
/∗ c h i a m a t a a l l a f u n z i o n e f i g l i o
∗ e r e c u p e r o d e l v a l o r e d i
∗ r i t o r n o ∗/
return ( f i g l i o ( i n d i c e ) ) ; case −1: /∗ e r r o r e ∗/
s n p r i n t f ( s t r i n g a , 2 5 6 , ” E r r o r e a l l a %d−ma f o r k \n” , i n d i c e ) ; w r i t e ( 2 , s t r i n g a , s t r l e n ( s t r i n g a ) ) ;
return ( 1 ) ; /∗ t e r m i n a z i o n e p a d r e ∗/
d e f a u l t : /∗ padre , c o n t i n u a ∗/
s n p r i n t f ( s t r i n g a , 2 5 6 , ” C r e a t o f i g l i o %d con p i d %d\n” , i n d i c e , p i d ) ;
w r i t e ( 1 , s t r i n g a , s t r l e n ( s t r i n g a ) ) ; }
}
/∗ i l p a d r e a r r i v a q u i dopo l e N c r e a z i o n i ∗/
f o r ( i n d i c e =0; i n d i c e < n f i g l i ; i n d i c e ++) {
/∗ l ’ o r d i n e i n c u i i f i g l i t e r m i n a n o NON e ’ p r e v e d i b i l e ,
∗ q u i n d i i l v a l o r e r e c u p e r a t o a l l a i −esima i t e r a z i o n e
∗ non n e c e s s a r i a m e n t e s i r i f e r i s c e a l l ’ i −esimo
∗ f i g l i o . ∗/
p i d=w a i t (& s t ) ;
s n p r i n t f ( s t r i n g a , 2 5 6 , ” I l f i g l i o con p i d %d r i t o r n a %d\n” , pid ,WEXITSTATUS( s t ) ) ;
w r i t e ( 1 , s t r i n g a , s t r l e n ( s t r i n g a ) ) ; }
return ( 0 ) ; }
/∗ Corpo d e l l a f u n z i o n e f i g l i o ∗/
i n t f i g l i o ( i n t argomento ) {
/∗ usa s t r i n g a p e r c h e ’ e ’ una v a r i a b i l e g l o b a l e ∗/
s n p r i n t f ( s t r i n g a , 2 5 6 , ” F i g l i o con i n d i c e %d\n” , argomento ) ; w r i t e ( 1 , s t r i n g a , s t r l e n ( s t r i n g a ) ) ;
return ( 0 ) ; }