Lab. di Sistemi Operativi - Esercitazione n 9- -Thread- 1
Sommario Esercizi su: Comunicazione tra processi: la funzione pipe() Condivisione dati e codice tra due o più processi: concetto di Thread 2
- Gestione dei processi - Comunicazione tra processi: la funzione pipe() 3
Esercizio n 1 fork + pipe - Scrivere un programma C in cui il processo di comunicazione tra padre e figlio è gestito da una pipe. Il programma dovrà quindi creare la pipe, generare il processo figlio PF che scriverà nella pipe una stringa inserita da tastiera. Il processo padre, visualizzerà sul video il contenuto della pipe. Esecuzione: $./a.out Introduci una stringa da scrivere nella pipe e premi [Enter] Output: Il padre ha letto nella pipe la stringa <aaaaaaaaaa> 4
Soluzione Esercizio n 1 #include <stdio.h> /* perror */ #include <errno.h> /* perror */ #include <unistd.h> /* write, lseek, close, exit */ #include <sys/types.h> /*open, lseek */ #include <sys/stat.h> /*open */ #include <fcntl.h> /*open*/ #define MAXLINE 256 int main (void) { int pid,fd[2]; /*contiene i due descrittori per accedere alla pipe in lettura ed in scrittura*/ int nread; char line[maxline]; if (pipe(fd)<0) { /*restituisce in fd due descrittori fd[0]: per la lettura e fd[1]: per la scrittura*/ perror("pipe"); exit(1); if((pid=fork())<0) /*Creazione di un nuovo processo */ {perror("fork"); exit(1); /*CONTINUA NELLA SLIDE SUCCESSIVA*/ 5
Soluzione Esercizio n 1 else if (pid==0) /* pid=0 : Processo figlio */ { printf("introduci una stringa da scrivere nella pipe e premi [Enter]\n"); scanf("%s",line); close(fd[0]); /*chiude il descrittore per leggere dalla pipe*/ /*Rimane bloccato nel write finchè la pipe è piena*/ write(fd[1],line,strlen(line)); /*Scrive la stringa nella pipe*/ else /* pid > 0 : Processo padre */ { close(fd[1]); /*chiude il descrittore per scrivere nella pipe*/ /*Rimane bloccato nel read finchè la pipe è vuota*/ nread = read(fd[0],line,maxline); /*Legge la stringa nella pipe*/ line [nread]='\0'; /*terminatore di null*/ printf("il padre ha letto nella pipe la stringa %s\n",line); exit(0); 6
Esercizio n 2 fork + pipe - Scrivere un programma C che prenda come parametro un file inputfile (controllare che il numero di argomenti passati sia corretto). Il programma dovrà aprire tale file, creare un processo figlio, PF che comunica con il processo padre mediante una pipe. Il processo figlio, leggerà i primi 10 caratteri di tale file, scrivendoli nella pipe, il padre, visualizzerà sul video i caratteri scritti dal figlio leggendoli dalla pipe Esempio inputfile 111111111122222222223333333333444444444455555555556666666666 Output: Il padre ha letto nella pipe la stringa 1111111111 7
Soluzione Esercizio n 2 #include <stdio.h> /* perror */ #include <errno.h> /* perror */ #include <unistd.h> /* write, lseek, close, exit */ #include <sys/types.h> /*open, lseek */ #include <sys/stat.h> /*open */ #include <fcntl.h> /*open*/ #define READLENGTH 10 main(int argc, char **argv) { int infile, fd[2], pid, nread; char buf[10]; if (argc!= 2) { printf ("uso: nomeprogramma <inputfile> \n"); exit (1); /* Apertura file inputfile*/ if ((infile=open(argv[1], O_RDONLY)) <0) { printf("errore apertura inputfile %s\n:",argv[1]); exit(1); if (pipe(fd)<0) {perror("pipe"); exit(1); /*CONTINUA NELLA SLIDE SUCCESSIVA*/ 8
Soluzione Esercizio n 2 /*Esecuzione fork*/ if ((pid = fork()) == -1) { perror("fork"); exit(1); else if (pid == 0) /*Processo Figlio*/ { close(fd[0]); /*chiude il descrittore di lettura della pipe*/ /*legge i primi 10 caratteri dal file*/ if ( (nread = read(infile, buf, READLENGTH)) <= 0) { close(infile); exit(1); /*scrive i primi 10 nella pipe*/ if ( (write(fd[1], buf, READLENGTH)) <= 0) { close(fd[1]); exit(1); close(fd[1]); exit(0); /*CONTINUA NELLA SLIDE SUCCESSIVA*/ 9
Soluzione Esercizio n 2 else { /*Processo Padre*/ close(fd[1]); /*chiude il descrittore per la scrittura sulla pipe*/ /*legge i primi 10 caratteri dalla pipe*/ if ( (nread = read(fd[0], buf, READLENGTH)) <= 0) { close(fd[0]); exit(1); /*scrive a video primi 10 caratteri*/ if ( (write(stdout_fileno, buf, READLENGTH)) <= 0) { close(fd[0]); exit(1); close(fd[0]); close(infile); exit(0); 10
Esercizio n 3 fork + 2 pipe (comunicazione bidirezionale) Scrivere un programma C che realizzi una comunicazione bidirezionale tra il processo padre ed il processo figlio mediante la creazione di due pipe distinte pipe1, pipe2 Il programma dovrà creare le due pipe ed il processo figlio. Il processo padre, scriverà sulla pipe1 (pdf1) un messaggio immesso da tastiera, il processo figlio leggerà tale messaggio dalla pipe1 (pdf1), lo stamperà a video e scriverà la notifica di lettura sulla pipe2 (pdf2) che verrà poi letta dal padre e stampata a video. (Utilizzare la funzione fgets per leggere un messaggio con spazi inserito da tastiera) Esecuzione:./a.out Inserire il messaggio e premere [ENTER] Output: Il processo figlio ha ricevuto il messaggio: <xxxxxx> Il processo padre ha ricevuto la notifica di lettura del messaggio <xxxxxx> 11
Soluzione Esercizio n 3 #include <stdio.h> /* perror */ #include <errno.h> /* perror */ #include <unistd.h> /* write, lseek, close, exit */ #include <sys/types.h> /*open, lseek */ #include <sys/stat.h> /*open */ #include <fcntl.h> /*open*/ #define SIZE 128 int main(int argc, char **argv) { int pfd1[2], pfd2[2]; /*descrittori di pipe*/ int nread, pid; char inbuf[size], outbuf[size]; if (pipe(pfd1)!=0 pipe(pfd2)!=0) { /*creazione delle due pipe*/ perror("pipe() fallita)"); exit(-1); if ((pid=fork()) < 0 ) { /*creazione del processo figlio*/ perror("fork() fallita"); exit(-2); /*CONTINUA NELLA SLIDE SUCCESSIVA*/ 12
Soluzione Esercizio n 3 if (pid==0) { /* figlio */ close(pfd1[1]); /*descrittore di lettura pipe1 */ close(pfd2[0]); /*descittore di scrittura pipe2 */ /* legge un messaggio dal padre */ nread=read(pfd1[0], inbuf, SIZE); /*legge il messaggio da pipe1*/ inbuf[nread]='\0'; /*terminatore di null */ close(pfd1[0]); printf("il figlio ha ricevuto il messaggio: %s\n", inbuf); /* manda un messaggio indietro di notifica lettura su pipe2*/ write(pfd2[1],inbuf,strlen(inbuf)); close(pfd2[1]); /*CONTINUA NELLA SLIDE SUCCESSIVA*/ 13
Soluzione Esercizio n 3 else { /* padre */ close(pfd1[0]); /*descrittore di scrittura pipe1 */ close(pfd2[1]); /*descrittore di lettura pipe2 */ printf("inserire il Messaggio e premere [ENTER]"); // legge un msg fgets(outbuf,size,stdin); // da tastiera write(pfd1[1], outbuf, strlen(outbuf)); /*Scrittura su pipe1 il mess*/ close(pfd1[1]); /* leggi il messaggio di notifica lettura del figlio */ nread = read(pfd2[0],inbuf,size); /*Lettura su pipe2*/ inbuf[nread]='\0'; /*terminatore di null */ close(pfd2[0]); printf("il padre ha ricevuto la notifica di lettura del messaggio: %s\n",inbuf); exit(0); 14
- CreazioneThread - 15
- CreazioneThread - Funzione pthread_create 16
- Terminare unthread - 17
- Aspettare la terminazione unthread - 18
Esercizio n 4 Thread (base) Scrivere un programma C che crea un Thread ed attende la terminazione dello stesso Compilazione: Opzione di compilazione $ gcc nomeprogramma.c -lpthread Esecuzione $./a.out Output Thread terminato con status: <valore status> 19
Soluzione Esercizio n 4 Thread #include <stdio.h> #include <pthread.h> #include <sys/types.h> // Funzione che verrà eseguita dal thread void *start(void* arg) { printf ("Sono un thread richiamato dal processo padre\n"); pthread_exit(0); main() { // Identificatore del thread pthread_t t; int status; if (pthread_create(&t, NULL, start, NULL)!= 0) { printf ("Errore nella creazione del nuovo thread\n"); exit(1); // Attende che il thread venga terminato pthread_join(t, &status); printf ("Il thread è terminato con status %d\n",status); - 20
Esercizio n 5 Thread (passaggio dei parametri) Scrivere un programma C che accetta un numero intero <n> da riga di comando, crea un Thread che sommerà ad una variabile globale intera di valore m il valore di n ed infine ne stampa il risultato a video. Compilazione: Opzione di compilazione $ gcc nomeprogramma.c -lpthread Esecuzione $./a.out <n> Output La somma di m + <n> è: xxx 21
Soluzione Esercizio n 5 Thread #include <sys/types.h> #include <unistd.h> Permette di passare alla #include <pthread.h> funzione somma strutture di diverso tipo #include <stdlib.h> #include <stdio.h> int m=10; /* Variabile globale modificata dal thread */ void *somma(void* arg) {//Funzione che verrà eseguita dal thread cast ad int del tipo void passato int *n = (int) arg; printf ( La somma di m + n è: %d\n", m + (*n)); sleep(2); /*Aspetta due secondi prima di terminare*/ pthread_exit(0); - 22
Soluzione Esercizio n 5 Thread main(int argc, char **argv) { pthread_t t; int status; int arg[1]; if (argc<2) { Passaggio printf ("uso: nome_programma <valore> \n"); parametri exit(1); alla arg[0]=atoi(argv[1]); /*valore da sommare*/ if (pthread_create(&t, NULL, somma, arg)!= 0) { printf ("Errore nella creazione del nuovo thread\n"); exit(1); // Attendo che il thread venga terminato pthread_join(t, &status); printf ("Il thread è terminato con status %d\n", status); - somma di funzione 23
Esercizio n 6 Thread (Memoria condivisa fra Thread) Scrivere un programma C che crea due Thread somma1 e somma2, entrambi accedono alle variabili test.a e test.b di una struttura dati test condivisa incrementandole di 1per 10 volte, aspettano 2 secondi prima di stampare a video i valori delle due variabile. Supporremo che tale accesso non venga regolamentato da alcun meccanismo di gestione della concorrenza. Compilazione: $ gcc nomeprogramma.c -lpthread Esecuzione $./a.out 24
Soluzione Esercizio n 6 Thread #include <stdio.h> #include <pthread.h> #include <unistd.h> #include <sys/types.h> #define CICLI 10 /*Costante usata per incrementare le variabili*/ struct test {/* Memoria Condivisa fra i thread */ int a; int b; mytest; /* dichiarazione delle due funzioni dei due thread*/ void *somma1(void *); void *somma2(void *); int main(void) { pthread_t som1tid, som2tid; /* Inizializzo la memoria condivisa */ mytest.a = 0; mytest.b = 0; - 25
Soluzione Esercizio n 6 Thread - /* A questo punto posso creare i thread */ if (pthread_create(&som1tid, NULL, somma, NULL)!= 0) { printf ("Errore nella creazione del thread somma1\n"); exit(1); /* A questo punto posso creare i thread... */ if (pthread_create(&som2tid, NULL, somma, NULL)!= 0) { printf ("Errore nella creazione del thread somma2\n"); exit(1); /* A questo punto aspetto che i due thread finiscano */ pthread_join(som1tid, NULL); pthread_join(som2tid, NULL); printf("e' finito il programma...\n"); exit (0); 26
Soluzione Esercizio n 6 Thread - void *somma(void *in) {//Funzione che verrà eseguita dai thread { int i; for(i=0; i<cicli; i++) { mytest.a++; mytest.b++; /* sleep di 2 secondi */ sleep(2); printf("somma1 -- a = %d \n", mytest.a); printf("somma1 -- b = %d \n", mytest.a); pthread_exit(0); 27
Soluzione Esercizio n 6 Thread - void *somma2(void *in) {//Funzione che verrà eseguita dal thread 2 { int i; for(i=0; i<cicli; i++) { mytest.a++; mytest.b++; /* sleep di 2 secondi */ sleep(2); printf("somma2 -- a = %d \n", mytest.a); printf("somma2 -- b = %d \n", mytest.b); pthread_exit(0); 28