├── 01introC ├── IntroPuntatori.pdf ├── StringheArgcArgv.pdf ├── argv.c ├── aritp.c ├── creafile.c ├── dentroScanf.pdf ├── dividi.c ├── elenco_primi_fun.c ├── leggi_interi.c ├── lunghezzaStringa.c ├── makefile ├── mergeSort.c ├── primi.c ├── scanf.c ├── scrivi_primi.c ├── somma.c └── sommad.c ├── 02struct ├── array_capitali.c ├── array_coppie.c ├── capitali.txt ├── citta.txt ├── funzfunz.c ├── lista_capitali.c ├── makefile ├── persone.txt ├── statiche.c └── stringole.c ├── 03makefile ├── bitops.c ├── invertifile.c ├── leggi_bin.c ├── legginomi.c ├── listastringhe.c ├── listastringhe.h ├── makefile ├── matrice.c ├── persone.txt ├── qsortint.c ├── qsortstr.c └── scrivi_primi_bin.c ├── 04assembler ├── Readme.md ├── bespin2.conf ├── filetypes.asm ├── makefile ├── primi.c ├── primo.s ├── strcmp.c ├── strcmp.s ├── tok.c └── tok.s ├── 05python ├── PyvsC.md ├── PyvsC.py ├── duplicati.py ├── esempi_classi.py ├── grande.py ├── recenti.py ├── recenti_ordinati.py ├── risultati.txt ├── serieA.py └── vip.py ├── 06processi ├── Mini introduzione alle System Calls.pdf ├── contaprimi.c ├── contaprimifile.c ├── fork_esempio.c ├── lettore.c ├── lettore.py ├── makefile ├── moria.c ├── npipe.c ├── numeri.py ├── xerrori.c └── xerrori.h ├── 07shmsem ├── contaprimi_sem.c ├── contaprimi_shm.c ├── makefile ├── shm0.c ├── shm_sort.c ├── shm_sort2.c ├── sommaprimi.c ├── sommaprimi_aux.c ├── sort3.c ├── xerrori.c └── xerrori.h ├── 08threads ├── ProdCons.pdf ├── TempiProdConsC.ods ├── contaprimi.c ├── divisori.c ├── divisori.py ├── esercizioDivisori.md ├── interi.py ├── makefile ├── pctest.c ├── prodcons.c ├── tabella_primi.c ├── xerrori.c └── xerrori.h ├── 09condvar ├── divisori.c ├── heap.c ├── makefile ├── rw.c ├── xerrori.c ├── xerrori.h └── zem.c ├── 10signals ├── MTSafety.pdf ├── makefile ├── segnali.c ├── segnaliRT.c ├── sigwait.c ├── xerrori.c └── xerrori.h ├── 11sockets ├── contaprimi.py ├── cserver.pdf ├── echo-client.py ├── echo-server.py ├── makefile ├── multipclient.py ├── pclient.c ├── pclient.py ├── poolpserver.py ├── pserver.py ├── selectpserver.py └── sommaprimi.py ├── LICENSE ├── README.md └── Registro.md /01introC/IntroPuntatori.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Laboratorio2B/2324-Lab2B/8000dd55ee0b9a79c6ad8dd690457f398e53e19a/01introC/IntroPuntatori.pdf -------------------------------------------------------------------------------- /01introC/StringheArgcArgv.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Laboratorio2B/2324-Lab2B/8000dd55ee0b9a79c6ad8dd690457f398e53e19a/01introC/StringheArgcArgv.pdf -------------------------------------------------------------------------------- /01introC/argv.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE // avverte che usiamo le estensioni GNU 2 | #include // permette di usare scanf printf etc ... 3 | #include // conversioni stringa/numero exit() etc ... 4 | #include // gestisce tipo bool (per variabili booleane) 5 | #include // permette di usare la funzione assert 6 | #include // funzioni di confronto/copia/etc di stringhe 7 | 8 | // le istruzioni qui sopra leggono i prototipi di alcune funzioni di libreria 9 | 10 | 11 | // Scopo del programma: 12 | // mostrare la struttura dell'array argv contenente i parametri 13 | // passati sulla linea di comando 14 | // mostrare la differenza fra copiare un puntatore e copiare 15 | // il contenuto dell'array (funzione strdup) 16 | 17 | 18 | // stampa un messaggio d'errore e termina il programma 19 | void termina(char *messaggio) 20 | { 21 | puts(messaggio); 22 | exit(1); 23 | } 24 | 25 | 26 | int main(int argc, char *argv[]) 27 | { 28 | 29 | // stampo gli elementi di argv[] come stringhe 30 | for(int i=0;i // permette di usare scanf printf etc ... 3 | #include // conversioni stringa/numero exit() etc ... 4 | #include // gestisce tipo bool (per variabili booleane) 5 | #include // permette di usare la funzione assert 6 | #include // funzioni di confronto/copia/etc di stringhe 7 | 8 | // esperimenti con l'artimetica dei puntatori 9 | 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | int a=1,b=2,c=3; 14 | int *v; 15 | v = malloc(10*sizeof(int)); 16 | for(int i=0;i<10;i++) 17 | v[i] = 10*i; 18 | 19 | printf("indirizzo di a=%p, contenuto di a: %d\n",&a,a); 20 | printf("indirizzo di b=%p, contenuto di b: %d\n",&b,b); 21 | printf("indirizzo di c=%p, contenuto di c: %d\n",&c,c); 22 | printf("indirizzo di v=%p, contenuto di v=%p\n",&v,v); 23 | 24 | 25 | //--- i due modi di utilizzare i puntatori sono interscambiabili: 26 | int *pb = &b; // pb contiene l'indirizzo di b 27 | c = v[0]; // metto v[0] in c 28 | a = *pb; // metto b in a 29 | // --- posso anche scrivere (meglio non farlo ma si può) 30 | c = *v; // equivalente a v[0] 31 | a = pb[0]; //equivalente a *pb 32 | // --- attenzione: stampo elemento inesistente 33 | c = 3; 34 | printf("pb=%p\n",pb); 35 | printf("pb[1]=%d (perché?)\n",pb[1]); 36 | printf("pb[2] (in base 16)=%x (perché?)\n",pb[2]); 37 | printf("pb[3] (in base 16)=%x (perché?)\n",pb[3]); 38 | 39 | // -------- Aritmetica dei puntatori: 40 | assert(v==&v[0]); // v contiene l'indirizzo di v[0] 41 | // &v[1]; // questo è l'indirizzo in memoria di v[1] 42 | // v+1; // questo è un modo leggittimo di indicare &v[1] 43 | printf("indirizzo di v[1]=%p, v+1=%p\n",&v[1],v+1); 44 | // questo vale anche fuori dall'array 45 | int i = 20; 46 | printf("indirizzo di v[%d]=%p, v+%d=%p\n",i,&v[i],i,v+i); 47 | 48 | 49 | // vediamo cosa succede per i caratteri 50 | char *s = argv[0]; 51 | printf("Valore s: %p, valore s+1: %p\n",s,s+1); 52 | // s+1 è l'indirizzo del carattere successivo 53 | // quindi dista 1 byte da s, notare la differenza con v+1 54 | // che dista 4 byte da v 55 | 56 | return 0; 57 | } 58 | 59 | -------------------------------------------------------------------------------- /01introC/creafile.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE // avverte che usiamo le estensioni GNU 2 | #include // permette di usare scanf printf etc ... 3 | #include // conversioni stringa/numero exit() etc ... 4 | #include // gestisce tipo bool (per variabili booleane) 5 | #include // permette di usare la funzione assert 6 | #include // funzioni di confronto/copia/etc di stringhe 7 | #include // richiesto per usare errno 8 | 9 | 10 | // scopo del programma: 11 | // mostrare come usare la funzione asprintf per creare 12 | // nuove stringhe combinando insieme stringhe e numeri 13 | 14 | // la stringa ottenuta da asprintf viene automaticamente 15 | // allocata della dimensione opportuna: il programma 16 | // deve provvedere alla deallocazione con free() 17 | 18 | 19 | // stampa un messaggio d'errore su stderr e termina il programma 20 | void termina(char *messaggio) 21 | { 22 | // se errno!=0 oltre al mio messaggio stampa il messaggio 23 | // associato alla variabile globale errno 24 | // utilizzando la funzione di libreria perror() 25 | if(errno!=0) perror(messaggio); 26 | // altrimenti stampa solo il mio messaggio 27 | else fprintf(stderr,"%s\n", messaggio); 28 | exit(1); 29 | } 30 | 31 | 32 | 33 | int main(int argc, char *argv[]) 34 | { 35 | int a; 36 | char *nome; 37 | 38 | puts("Inserisci il nome e il numero di file:"); 39 | int e = scanf("%ms %d",&nome,&a); 40 | if(e!=2) termina("Errore scanf"); 41 | 42 | 43 | // genera i nomi e scrive i file 44 | for(int i=0;i // permette di usare scanf printf etc ... 3 | #include // conversioni stringa/numero exit() etc ... 4 | #include // gestisce tipo bool (per variabili booleane) 5 | #include // permette di usare la funzione assert 6 | #include // funzioni di confronto/copia/etc di stringhe 7 | #include // necessaria per usare errno 8 | 9 | 10 | // Esercizio svolto in aula 11 | // Scrivere un programma che legge dalla linea di comando 12 | // il nome di un file di testo contenente valori interi 13 | // e crea due file con estensione .pari e .dispari 14 | // contenenti rispettivamente gli interi pari e dispari 15 | // del file originale 16 | 17 | 18 | 19 | // stampa un messaggio d'errore su stderr e termina il programma 20 | void termina(char *messaggio) 21 | { 22 | // se errno!=0 oltre al mio messaggio stampa il messaggio 23 | // associato alla variabile globale errno 24 | // utilizzando la funzione di libreria perror() 25 | if(errno!=0) perror(messaggio); 26 | // altrimenti stampa solo il mio messaggio 27 | else fprintf(stderr,"%s\n", messaggio); 28 | exit(1); 29 | } 30 | 31 | 32 | int main(int argc, char *argv[]) 33 | { 34 | // verifica siano stati forniti esattamente 2 parametri 35 | if(argc!=2) { 36 | printf("Uso: %s nome_file\n",argv[0]); 37 | return 1; 38 | } 39 | // copia il puntatore nella variabile nome_file 40 | char *nome_file = argv[1]; 41 | 42 | // apro il file in lettura 43 | FILE *f = fopen(nome_file,"rt"); 44 | if(f==NULL) termina("Apertura file fallita"); 45 | 46 | // creo il file con estensione .pari 47 | char *nomepari = malloc(strlen(nome_file)+6); 48 | if(nomepari==NULL) termina("Allocazione fallita"); 49 | strcpy(nomepari,nome_file); 50 | strcat(nomepari,".pari"); 51 | FILE *fp = fopen(nomepari,"wt"); 52 | free(nomepari); // non essendo più necessaria dealloco la stringa 53 | if(fp==NULL) termina("Errore creazione file pari"); 54 | 55 | // creo il file con estensione .dispari 56 | char *nomedispari = malloc(strlen(nome_file)+9); 57 | if(nomedispari==NULL) termina("Allocazione fallita"); 58 | strcpy(nomedispari,nome_file); 59 | strcat(nomedispari,".dispari"); 60 | FILE *fd = fopen(nomedispari,"wt"); 61 | free(nomedispari); // non essendo più necessaria dealloco la stringa 62 | if(fd==NULL) termina("Errore creazione file dispari"); 63 | 64 | // leggo tutti gli interi e li riscrivo nel file appropriato 65 | while(true) { 66 | int n; 67 | int e = fscanf(f,"%d",&n); 68 | if(e==EOF) break; 69 | if(e!=1) termina("Contenuto illegale nel file"); 70 | if(n%2==0) 71 | fprintf(fp,"%d\n",n); 72 | else 73 | fprintf(fd,"%d\n",n); 74 | } 75 | 76 | // chiudi tutti i file e termina 77 | if(fclose(f)==EOF) 78 | termina("Errore chiusura file");; 79 | if(fclose(fp)==EOF) 80 | termina("Errore chiusura file");; 81 | if(fclose(fd)==EOF) 82 | termina("Errore chiusura file");; 83 | 84 | return 0; 85 | } 86 | 87 | -------------------------------------------------------------------------------- /01introC/elenco_primi_fun.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE // avverte che usiamo le estensioni GNU 2 | #include // permette di usare scanf printf etc ... 3 | #include // conversioni stringa/numero exit() etc ... 4 | #include // gestisce tipo bool (per variabili booleane) 5 | #include // permette di usare la funzione assert 6 | #include // funzioni di confronto/copia/etc di stringhe 7 | 8 | // le istruzioni qui sopra leggono i prototipi di alcune funzioni di libreria 9 | 10 | // da compilare con: 11 | // gcc -std=c11 -Wall -O -g -o elenco_primi_fun elenco_primi_fun.c 12 | 13 | 14 | // Scopo del programma: 15 | // mostrare come si dichiarano e utilizzano le funzioni che 16 | // hanno degli array come parametri di input e/o output 17 | 18 | 19 | 20 | // prototipo della funzione primo() 21 | // bool primo(int k); 22 | // non necessario in quanto la definizione è prima del main 23 | 24 | 25 | 26 | // dato k restituisco true se è primo, false altrimenti 27 | bool primo(int k) 28 | { 29 | if(k%2==0) 30 | return k==2; 31 | // era uguale scrivere 32 | // if(k==2) return true; 33 | // else return false; 34 | // ma scrivere return k==2 è più breve e (per me) più chiaro 35 | 36 | // mi occupo del caso k dispari 37 | for(int i=3; ik) break; 40 | } 41 | return true; 42 | } 43 | 44 | 45 | // stampa un messaggio d'errore e termina il programma 46 | void termina(char *messaggio) 47 | { 48 | puts(messaggio); 49 | exit(1); 50 | } 51 | 52 | // input: intero n 53 | // output: array dei primi <=n 54 | int *elenco_primi(int n, int *p) 55 | { 56 | 57 | printf("Valore di p: %ld\n", (long) p); 58 | printf("Valore a cui punta p: %d\n", *p); 59 | 60 | // crea un array dinamico inizialmente di 10 elementi 61 | int *a; // dichiaro che a sarà usata come array 62 | int size = 10; // dimensione attuale dell'array 63 | int messi = 0; // numero di elementi attualmente dentro l'array 64 | a = malloc(size*sizeof(int)); 65 | if(a==NULL) termina("Malloc fallita"); 66 | 67 | // riempio array 68 | for(int i=2; i<=n; i++) { 69 | if(primo(i)) { 70 | // se l'intero i è primo lo inserisco 71 | // nella tabella dei primi 72 | // ma prima verifico che ci sia spazio 73 | if(messi==size) { 74 | size = 2*size; // se la tabella è piena raddoppio la dimensione 75 | a = realloc(a,size*sizeof(int)); 76 | if(a==NULL) termina("Realloc fallita"); 77 | } 78 | // inserisco il numero primo i dentro a[] 79 | a[messi] = i; 80 | messi += 1; 81 | } 82 | } 83 | // tabella completata 84 | // riduco array alla dimensione minima 85 | a = realloc(a,messi*sizeof(int)); 86 | if(a==NULL) termina("Realloc fallita"); 87 | *p = messi; // va a scrivere in quanti 88 | // la dimensione dell'array 89 | return a; 90 | } 91 | 92 | 93 | // funzione che stampa l'array che inizia in b 94 | // e contiene k elementi 95 | void stampa_array_int(int b[], int k) 96 | { 97 | // stampa contenuto array, usando 8 caratteri per intero 98 | for(int i=0;i // permette di usare scanf printf etc ... 3 | #include // conversioni stringa/numero exit() etc ... 4 | #include // gestisce tipo bool (per variabili booleane) 5 | #include // permette di usare la funzione assert 6 | #include // funzioni di confronto/copia/etc di stringhe 7 | #include // necessaria per usare errno 8 | 9 | 10 | // Scopo del programma: 11 | // mostrare come si legge da un file di testo 12 | 13 | 14 | // stampa un messaggio d'errore su stderr e termina il programma 15 | void termina(char *messaggio) 16 | { 17 | // se errno!=0 oltre al mio messaggio stampa il messaggio 18 | // associato alla variabile globale errno 19 | // utilizzando la funzione di libreria perror() 20 | if(errno!=0) perror(messaggio); 21 | // altrimenti stampa solo il mio messaggio 22 | else fprintf(stderr,"%s\n", messaggio); 23 | exit(1); 24 | } 25 | 26 | // legge gli interi che sono nel file f 27 | // e li salva in un array che viene restituito 28 | // con return + passaggio per riferimento 29 | int *leggi_file(FILE *f, int *num_elementi) 30 | { 31 | assert(f!=NULL); // il file deve essere valido 32 | int size=10; // dimensione attuale dell'array 33 | int messi=0; // numero di elementi attualmente nell'array 34 | int *a = malloc(size*sizeof(int)); 35 | if(a==NULL) 36 | termina("Memoria insufficiente"); 37 | 38 | while(true) { 39 | int n; 40 | int e = fscanf(f,"%d",&n); 41 | if(e==EOF) break; 42 | if(e!=1) termina("Contenuto illegale nel file"); 43 | // ho letto un intero dal file ed è stato messo in n 44 | if(messi==size) { 45 | // ingrandisco l'array 46 | size = size*2; 47 | a = realloc(a,size*sizeof(int)); 48 | if(a==NULL) 49 | termina("realloc fallita"); 50 | } 51 | assert(size>messi); 52 | a[messi] = n; 53 | messi += 1; 54 | } 55 | // ho messo tutti gli elementi che mi interessavano 56 | size = messi; 57 | a = realloc(a,size*sizeof(int)); 58 | if(a==NULL) 59 | termina("realloc fallita"); 60 | // salvo il numero di elementi e restituisco l'array 61 | *num_elementi = messi; 62 | return a; 63 | } 64 | 65 | // visualizza elementi di un qualsiasi 66 | // array di int sul terminale 67 | void stampa_array(int *a, int n) 68 | { 69 | assert(a!=NULL); 70 | // stampo il contenuto dell'array 71 | for(int i=0;i // permette di usare scanf printf etc ... 5 | #include // conversioni stringa/numero exit() etc ... 6 | #include // gestisce tipo bool 7 | #include // permette di usare la funzione assert 8 | #include // funzioni per stringhe 9 | #include // rischiesto per usare errno 10 | 11 | void termina(const char *messaggio); 12 | 13 | 14 | // funzione semplice per calcolare la lunghezza di una stringa: 15 | // conto quanti caratteri vedo prima di raggiungere lo \0 16 | int lung_stringa1(const char s[]) 17 | { 18 | assert(s!=NULL); 19 | int i=0; 20 | while(s[i] != '\0') 21 | i++; 22 | return i; 23 | } 24 | 25 | 26 | // usa *(s+i) invece di s[i] 27 | int lung_stringa2(char s[]) 28 | { 29 | int i=0; 30 | while(*(s+i) != '\0') // s+i == &s[i] , quindi *(s+i)=s[i] 31 | i++; 32 | return i; 33 | } 34 | 35 | // incrementa s invece di scrivere s+i 36 | // non c'è motivo di usarlo ma bisogna saperlo riconoscere 37 | int lung_stringa3(const char s[]) 38 | { 39 | int i=0; 40 | while(*s != '\0') { // s+i == &s[i] , quindi *(s+i)=s[i] 41 | i++; s++; // s++ equivalente s = s+1 42 | } 43 | return i; 44 | } 45 | 46 | // incrementa s dentro il test del while. Poco leggibile: 47 | // sfrutta il fatto che ++ ha precedenza maggiore di * 48 | int lung_stringa4(char s[]) 49 | { 50 | int i=0; 51 | while(*s++ != '\0') // s+i == &s[i] , quindi *(s+i)=s[i] 52 | i++; // s++ equivalente s = s+1 53 | return i; 54 | } 55 | 56 | 57 | // legge una stringa dalla linea di comando e ne 58 | // calcola la lunghezza con le differenti funzioni 59 | int main(int argc, char *argv[]) 60 | { 61 | 62 | if(argc!=2) { 63 | fprintf(stderr, "Uso:\n\t %s stringa\n", argv[0]); 64 | exit(1); 65 | } 66 | 67 | int n = lung_stringa1(argv[1]); 68 | printf("lungh_stringa1: %d\n",n); 69 | n = lung_stringa2(argv[1]); 70 | printf("lungh_stringa2: %d\n",n); 71 | n = lung_stringa3(argv[1]); 72 | printf("lungh_stringa3: %d\n",n); 73 | n = lung_stringa4(argv[1]); 74 | printf("lungh_stringa4: %d\n",n); 75 | return 0; 76 | } 77 | 78 | 79 | // stampa su stderr il messaggio che gli passo 80 | // se errno!=0 stampa anche il messaggio d'errore associato 81 | // a errno. dopo queste stampe termina il programma 82 | void termina(const char *messaggio) 83 | { 84 | if(errno==0) 85 | fprintf(stderr,"%s\n",messaggio); 86 | else 87 | perror(messaggio); 88 | exit(1); 89 | } 90 | -------------------------------------------------------------------------------- /01introC/makefile: -------------------------------------------------------------------------------- 1 | # il funzionamento del makefile lo vedremo prossimamente 2 | 3 | # definizione del compilatore e dei flag di compilazione 4 | # che vengono usate dalle regole implicite 5 | CC=gcc 6 | CFLAGS=-std=c11 -Wall -O -g 7 | LDLIBS=-lm 8 | 9 | # elenco degli eseguibili da creare 10 | all: somma sommad primi elenco_primi_fun scrivi_primi leggi_interi \ 11 | aritp lunghezzaStringa mergeSort scanf 12 | 13 | 14 | -------------------------------------------------------------------------------- /01introC/mergeSort.c: -------------------------------------------------------------------------------- 1 | // Algoritmo Mergesort che sfrutta la notazione &a[n1] per ottenere 2 | // il puntatore all'inizio dell'array contenente al seconda metà 3 | // dell'input. 4 | 5 | #define _GNU_SOURCE // avverte che usiamo le estensioni GNU 6 | #include // permette di usare scanf printf etc ... 7 | #include // conversioni stringa/numero exit() etc ... 8 | #include // gestisce tipo bool 9 | #include // permette di usare la funzione assert 10 | #include // funzioni per stringhe 11 | #include // rischiesto per usare errno 12 | 13 | // prototipi delle funzioni che appaiono dopo il main() 14 | void stampa_array(int *a, int n, FILE *f); 15 | void termina(char *messaggio); 16 | 17 | 18 | // funzione per il merge di due array in un terzo 19 | // merge di a[0...n1-1] e c[0... n2-1] dentro b[] 20 | // Soluzione proposta da co-pilot apparentemente corretta 21 | void merge(int a[], int na, int c[], int nc, int b[]) 22 | { 23 | assert(a!=NULL); 24 | assert(c!=NULL); 25 | assert(b!=NULL); 26 | assert(na>0); 27 | assert(nc>0); 28 | 29 | int i=0; // indice per a[] 30 | int j=0; // indice per c[] 31 | int k=0; // indice per b[] 32 | 33 | // scorro a[] e c[] e copio il minore in b[] 34 | while(i0); 69 | 70 | // caso base 71 | if(n==1) return; 72 | 73 | int n1 = n/2; // dimesione prima parte 74 | int n2 = n - n1; // dimensione seconda parte 75 | 76 | mergesort(a,n1); 77 | mergesort(&a[n1],n2); // &a[n1] potevo scriverlo a+n1 78 | 79 | // ho le due metà ordinate devo fare il merge 80 | int *b = malloc(n*sizeof(*b)); 81 | if(b==NULL) termina("malloc fallita nel merge"); 82 | merge(a,n1,&a[n1],n2,b); 83 | // copio il risultato da b[] ad a[] 84 | for(int i=0;i // permette di usare scanf printf etc ... 3 | #include // conversioni stringa/numero exit() etc ... 4 | #include // gestisce tipo bool (per variabili booleane) 5 | #include // permette di usare la funzione assert 6 | #include // funzioni di confronto/copia/etc di stringhe 7 | 8 | // Come detto a lezione, le istruzioni #include qui sopra 9 | // leggono dei file che contengono i prototipi delle funzioni 10 | // di libreria che usiamo nel programma (tipo malloc/printf/exit ...) 11 | // Quale include deve essere specificato per ogni funzione 12 | // e indicato nella pagina man della funzione 13 | 14 | // Per ottenere la lista delle directory nelle quali i file .h 15 | // vengono cercati dal compilatore scrivete sulla linea di comando 16 | // gcc -xc /dev/null -E -Wp,-v 2>&1 | sed -n 's,^ ,,p' 17 | 18 | 19 | // da compilare con: 20 | // gcc -std=c11 -Wall -O -g -o primi primi.c 21 | // oppure con il makefile visto a lezione 22 | 23 | 24 | // Scopo del programma: 25 | // legge un intero N da tastiera 26 | // crea un array *dinamico* con i primi <=N 27 | 28 | // prototipo della funzione primo() 29 | // bool primo(int k); 30 | // non necessario in quanto la definizione è prima del main 31 | 32 | // prototipo della funzione termina() 33 | // il corpo della funzione può apparire dopo il main() 34 | void termina(char *messaggio); 35 | 36 | 37 | // dato k restituisco True se è primo, false altrimenti 38 | // suggerito da copilot (non è bellissimo ma è corretto) 39 | bool primo(int k) { 40 | // se k è pari e diverso da 2 allora non è primo 41 | if(k%2==0 && k!=2) return false; 42 | // se k è dispari e non è primo 43 | // allora esiste un divisore <= sqrt(k) 44 | // che è dispari 45 | // quindi posso controllare solo i divisori dispari 46 | // e posso fermarmi a sqrt(k) 47 | for(int i=3; i*i<=k; i+=2) { 48 | if(k%i==0) return false; 49 | } 50 | return true; 51 | } 52 | 53 | 54 | 55 | 56 | 57 | int main(int argc, char *argv[]) 58 | { 59 | int n; // definisco variabile intera di nome n 60 | 61 | // spiego cosa voglio leggere e lo leggo con scanf 62 | printf("Inserisci il valore N: "); 63 | int *m = &n; 64 | int e = scanf("%d",m); // il motivo della & lo vedremo più avanti 65 | // controlli sulla lettura 66 | if(e!=1) termina("Valore non trovato"); 67 | if(n<2) termina("Non ci sono numeri primi"); 68 | 69 | 70 | // crea un array dinamico inizialmente di 10 elementi 71 | int *a; // dichiaro che a sarà usata come array 72 | int size = 10; // dimensione attuale dell'array 73 | int messi = 0; // numero di elementi attualmente dentro l'array 74 | a = malloc(size*sizeof(int)); 75 | if(a==NULL) 76 | termina("Malloc fallita"); 77 | 78 | 79 | // riempio array 80 | for(int i=2; i<=n; i++) { 81 | if(primo(i)) { 82 | // se l'intero i è primo lo inserisco 83 | // nella tabella dei primi 84 | // ma prima verifico che ci sia spazio 85 | if(messi==size) { 86 | size = 2*size; // se la tabella è piena raddoppio la dimensione 87 | a = realloc(a,size*sizeof(int)); 88 | if(a==NULL) 89 | termina("Realloc fallita"); 90 | } 91 | // inserisco il primo i dentro a[] 92 | a[messi] = i; 93 | messi += 1; 94 | } 95 | } 96 | // tabella completata 97 | // riduco array alla dimensione minima 98 | a = realloc(a,messi*sizeof(int)); 99 | if(a==NULL) termina("Realloc fallita"); 100 | 101 | // stampa contenuto array, usando 8 caratteri per intero 102 | for(int i=0;i // permette di usare scanf printf etc ... 3 | #include // conversioni stringa/numero exit() etc ... 4 | #include // gestisce tipo bool (per variabili booleane) 5 | #include // permette di usare la funzione assert 6 | #include // funzioni di confronto/copia/etc di stringhe 7 | #include // rischiesto per usare errno 8 | 9 | 10 | // scopo del programma: 11 | // mostrare le opzioni di come leggere delle stringhe con 12 | // fscanf (e simili, tipo fscanf) 13 | // Fare riferimento ai lucidi dentroScanf.pdf 14 | 15 | // Ricordare che l'uso di scanf("%s"...) è un'operazione 16 | // a rischio di buffer overflow in quanto 17 | // è possibile scrivere in zone esterne a quelle allocate al programma 18 | 19 | 20 | // stampa un messaggio d'errore su stderr e termina il programma 21 | void termina(const char *messaggio); 22 | 23 | 24 | int main(int argc, char *argv[]) 25 | { 26 | int a=1; 27 | char s[12]; 28 | char *z=NULL; 29 | puts("Inserisci un numero e due stringhe"); 30 | int e = scanf("%d %11s %ms",&a,s,&z); 31 | if(e!=3) termina("Errore scanf"); 32 | 33 | printf("a=%d,s=%s,z=%s\n",a,s,z); 34 | 35 | // libero memoria allocata da scanf 36 | free(z); 37 | 38 | // %11s garantisce che vengono letti al più 12 caratteri (11+\0) 39 | // e quindi rimaniamo dentro s[12] 40 | 41 | // %ms delega il compito di allocare la memoria a scanf 42 | // devo ricordarmi il passaggio per riferimento 43 | // e di eseguire la free() quando la stringa non è più necessaria 44 | 45 | 46 | return 0; 47 | } 48 | 49 | 50 | 51 | void termina(const char *messaggio) 52 | { 53 | // se errno!=0 oltre al mio messaggio stampa il messaggio 54 | // associato alla variabile globale errno 55 | // utilizzando la funzione di libreria perror() 56 | if(errno!=0) perror(messaggio); 57 | // altrimenti stampa solo il mio messaggio 58 | else fprintf(stderr,"%s\n", messaggio); 59 | exit(1); 60 | } 61 | 62 | -------------------------------------------------------------------------------- /01introC/scrivi_primi.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE // avverte che usiamo le estensioni GNU 2 | #include // permette di usare scanf printf etc ... 3 | #include // conversioni stringa/numero exit() etc ... 4 | #include // gestisce tipo bool (per variabili booleane) 5 | #include // permette di usare la funzione assert 6 | #include // funzioni di confronto/copia/etc di stringhe 7 | #include // necessaria per usare errno 8 | 9 | 10 | // dato k restituisco true se è primo, false altrimenti 11 | bool primo(int k) 12 | { 13 | assert(k>0); 14 | if(k%2==0) 15 | return k==2; // se k è pari allora è primo se e solo se k==2 16 | 17 | // mi occupo ora del caso k dispari 18 | assert(k%2!=0); 19 | for(int i=3; ik) break; 22 | } 23 | return true; 24 | } 25 | 26 | 27 | // stampa un messaggio d'errore e termina il programma 28 | void termina(char *messaggio) 29 | { 30 | // se errno!=0 oltre al mio messaggio stampa il messaggio 31 | // associato alla variabile globale errno 32 | // utilizzando la funzione di libreria perror() 33 | if(errno!=0) perror(messaggio); 34 | // altrimenti stampa solo il mio messaggio 35 | else fprintf(stderr,"%s\n", messaggio); 36 | exit(1); 37 | } 38 | 39 | 40 | int main(int argc, char *argv[]) 41 | { 42 | // verifica siano stati forniti esattamente 2 parametri 43 | if(argc!=3) { 44 | printf("Uso: %s N nome_file\n",argv[0]); 45 | return 1; 46 | } 47 | // converte il primo parametro in un intero 48 | int n = atoi(argv[1]); 49 | if(n<=0) termina("Il parametro n deve essere positivo"); 50 | // copia il puntatore nella variabile nome_file 51 | char *nome_file = argv[2]; 52 | 53 | // apro il file in scrittura 54 | FILE *f = fopen(nome_file,"wt"); 55 | if(f==NULL) termina("Apertura file fallita"); 56 | 57 | // cerca i primi da 2 a n e li scrive dentro il file 58 | for(int i=2;i<=n;i++) { 59 | // if(i==14) rewind(f); // esperimento con rewind fatto in aula 60 | if(primo(i)) { 61 | int e = fprintf(f,"%d\n",i); //scrive i nel file 62 | if(e<0) termina("Errore nella scrittura"); 63 | } 64 | } 65 | 66 | // chiudi il file e termina 67 | if(fclose(f)==EOF) 68 | termina("Errore chiusura file");; 69 | 70 | return 0; 71 | } 72 | 73 | -------------------------------------------------------------------------------- /01introC/somma.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE // avverte che usiamo le estensioni GNU 2 | #include // permette di usare scanf printf etc ... 3 | #include // conversioni stringa/numero exit() etc ... 4 | #include // gestisce tipo bool (per variabili booleane) 5 | #include // permette di usare la funzione assert 6 | #include // funzioni di confronto/copia/etc di stringhe 7 | 8 | // le istruzioni qui sopra le spieghiamo più avanti 9 | 10 | // da compilare con: 11 | // gcc -std=c11 -Wall -O -g -o somma somma.c 12 | 13 | 14 | // Scopo del programma: 15 | // legge un intero N da tastiera 16 | // crea un array di N int 17 | // legge N interi mettendoli nell'array 18 | // calcola la somma degli elementi dell'array 19 | // stampa la somma 20 | 21 | int main(int argc, char *argv[]) 22 | { 23 | int n; // definisco variabile intera di nome n 24 | 25 | // spiego cosa voglio leggere e lo leggo con scanf 26 | printf("Inserisci il numero di elementi: "); 27 | int e = scanf("%d",&n); // il motivo della & lo vedremo più avanti 28 | // controlli sulla lettura 29 | if(e!=1) { 30 | puts("Valore non trovato"); 31 | exit(1); 32 | } 33 | if(n<=0) { 34 | puts("Il numero di elementi deve essere positivo"); 35 | exit(2); 36 | } 37 | 38 | // crea e riempi array 39 | int a[n]; 40 | for(int i=0; i // permette di usare scanf printf etc ... 3 | #include // conversioni stringa/numero exit() etc ... 4 | #include // gestisce tipo bool (per variabili booleane) 5 | #include // permette di usare la funzione assert 6 | #include // funzioni di confronto/copia/etc di stringhe 7 | 8 | // le istruzioni qui sopra le spieghiamo più avanti 9 | 10 | // da compilare con: 11 | // gcc -std=c11 -Wall -O -g -o sommad sommad.c 12 | 13 | 14 | // Scopo del programma: 15 | // legge un intero N da tastiera 16 | // crea un array *dinamico* di N int 17 | // legge N interi mettendoli nell'array 18 | // calcola la somma degli elementi dell'array 19 | // stampa la somma 20 | 21 | int main(int argc, char *argv[]) 22 | { 23 | int n; // definisco variabile intera di nome n 24 | 25 | // spiego cosa voglio leggere e lo leggo con scanf 26 | printf("Inserisci il numero di elementi: "); 27 | int e = scanf("%d",&n); // il motivo della & lo vedremo più avanti 28 | // controlli sulla lettura 29 | if(e!=1) { 30 | puts("Valore non trovato"); 31 | exit(1); 32 | } 33 | if(n<=0) { 34 | puts("Il numero di elementi deve essere positivo"); 35 | exit(2); 36 | } 37 | 38 | // crea un array dinamico e riempi array 39 | int *a; // dichiaro che a sarà usata come array 40 | a = malloc(n*sizeof(int)); 41 | if(a==NULL) { 42 | puts("Malloc fallita"); 43 | exit(3); 44 | } 45 | 46 | for(int i=0;i // permette di usare scanf printf etc ... 3 | #include // conversioni stringa exit() etc ... 4 | #include // gestisce tipo bool 5 | #include // permette di usare la funzione assert 6 | #include // funzioni per stringhe 7 | #include // rischiesto per usare errno 8 | 9 | // prototipi delle funzioni che appaiono dopo il main() 10 | void termina(const char *messaggio); 11 | 12 | // Scopo del programma: 13 | // Mostrare come si definiscono e usano le struct 14 | 15 | 16 | // keyword typedef: per definire sinonimi di tipi esistenti 17 | // ad esempio posso metetre le istruzioni (fuori da ogni funzione) 18 | typedef int intero; 19 | typedef int *puntatore_a_int; 20 | // e nel resto del programma posso scrivere "intero" invece di "int" 21 | // e "puntatore_a_int" invece di "int *" 22 | 23 | 24 | // E' molto frequente l'uso combinato di struct 25 | // (definisce nuovi tipi) e typdef (definisce un sinonimo) 26 | // Esempio: definisco la struct duetto 27 | // dico che coppia è sinonimo di struct duetto 28 | typedef struct duetto { 29 | int primo; 30 | int secondo; 31 | } coppia; 32 | // nel resto del programma posso usare liberamente "coppia" o "struct duetto" 33 | 34 | 35 | // scambia le componenti: il parametro d è passato per valore 36 | // quindi la funzione opera su una copia locale di d 37 | // e la modifica non ha effetto sul chiamante 38 | struct duetto scambia(struct duetto d) 39 | { 40 | intero tmp = d.primo; 41 | d.primo = d.secondo; 42 | d.secondo = tmp; 43 | return d; 44 | } 45 | 46 | // stampa su f la coppia passata per valore 47 | void coppia_stampa(coppia a, FILE *f) { 48 | fprintf(f,"(%d,%d)\n",a.primo,a.secondo); 49 | } 50 | 51 | // stampa su f la coppia passata per indirizzo 52 | // const indica che la funzione non può modificare 53 | // la coppia a cui punta il parametro a 54 | // si passa il parametro per indirizzo per evitare di fare 55 | // una copia della struct da stampare che potrebbe essere 56 | // molto grande (in questo caso no: sono solo 2 interi) 57 | void pcoppia_stampa(const coppia *a, FILE *f) { 58 | fprintf(f,"(%d,%d)\n",(*a).primo,(*a).secondo); 59 | } 60 | 61 | // incrementa di 1 entrambe le componenti della coppia 62 | // il parametro a è passato per indirizzo 63 | // quindi la funzione modifica la coppia a cui punta a 64 | void incrementa(coppia *a) { 65 | (*a).primo +=1; // come visto ao lezione le parentesi sono necessarie 66 | a->secondo +=1; // l'uso di a-> al posto di (*a). è equivalente e molto usato 67 | } 68 | 69 | 70 | // esempio di costruzione di un array di coppie e di uso delle funzioni 71 | // viste sopra 72 | int main(int argc, char *argv[]) 73 | { 74 | coppia *a; 75 | 76 | if(argc <3 || argc%2==0) { 77 | printf("Uso: %s un numero positivo pari di interi\n",argv[0]); 78 | exit(1); 79 | } 80 | int n = (argc-1)/2; // dimensione di a == numero coppie 81 | a = malloc(n*sizeof(coppia)); 82 | if(a==NULL) termina("allocazione fallita"); 83 | 84 | // crea l'array e incrementa di 1 entrambe le componenti di ogni coppia 85 | for(int i=0;i 2 | #include 3 | #include 4 | #include 5 | 6 | // prototipo di applica: il terzo argomento ha come tipo: 7 | // puntatore a funzione che prende come input due interi e 8 | // restituisce un intero 9 | int applica(int x, int y, int (*f)(int, int)); 10 | 11 | 12 | // funzioni somma e prodotto che prendono come 13 | // input due interi e restituiscono un intero 14 | int somma(int a, int b) 15 | { 16 | return a+b; 17 | } 18 | 19 | int prod(int a, int b) 20 | { 21 | return a*b; 22 | } 23 | 24 | 25 | int main(int argc, char *argv[]) 26 | { 27 | int a,b; 28 | 29 | if (argc!=3) { 30 | fprintf(stderr,"Uso:\n\t%s a b\n",argv[0]); exit(1); 31 | } 32 | a = atoi(argv[1]); 33 | b = atoi(argv[2]); 34 | printf("Somma: %d, Prodotto %d\n", 35 | applica(a,b,&somma), 36 | applica(a,b,&prod)); 37 | return 0; 38 | } 39 | 40 | // funzione che prende in input due interi e una funzione 41 | // e applica la funzione ai due interi 42 | int applica(int x, int y, int (*f)(int, int)) { 43 | int z = f(x,y); 44 | return z; 45 | } 46 | 47 | 48 | -------------------------------------------------------------------------------- /02struct/makefile: -------------------------------------------------------------------------------- 1 | # il funzionamento del makefile lo vedremo prossimamente 2 | 3 | # definizione del compilatore e dei flag di compilazione 4 | # che vengono usate dalle regole implicite 5 | CC=gcc 6 | CFLAGS=-std=c11 -Wall -g 7 | LDLIBS=-lm 8 | 9 | # elenco degli eseguibili da creare 10 | all: array_coppie array_capitali funzfunz lista_capitali stringole statiche 11 | 12 | -------------------------------------------------------------------------------- /02struct/persone.txt: -------------------------------------------------------------------------------- 1 | Bruce Wayne; James Gordon 2 | Denethor; Boromir; Faramir 3 | 4 | Coriolanus Snow; Cinna; Caesar Flickerman; 5 | Marty McFly; Emmett Brown 6 | Oliver Queen; 7 | Barry Allen; Iris West; Caitlin Snow; Francisco Ramon 8 | Morpheus; Trinity; ;Neo; Niobe 9 | -------------------------------------------------------------------------------- /02struct/statiche.c: -------------------------------------------------------------------------------- 1 | /* ********************************************************* 2 | * Esempio uso varabili statiche 3 | * ********************************************************* */ 4 | #include // permette di usare scanf printf etc ... 5 | #include // conversioni stringa/numero rand() abs() exit() etc ... 6 | #include // gestisce tipo bool (per variabili booleane) 7 | #include // permette di usare la funzione assert 8 | #include // prototipi delle funzioni per la manipolazione delle stringhe 9 | 10 | 11 | // esempio di funzione con variabile statica 12 | int funz(int x) 13 | { 14 | static int y=3; // questa inizializzazione avviene solo alla prima esecuzione 15 | int z = x+y; 16 | y += 1; // il valore di y viene incrementato di uno ad ogni esecuzione della funzione 17 | if(x==0) y=3; 18 | return z; 19 | } 20 | 21 | // invoca funz() per ogni intero passato sulla linea di comando 22 | int main(int argc, char *argv[]) 23 | { 24 | for(int i=1;i // permette di usare scanf printf etc ... 3 | #include // conversioni stringa/numero exit() etc ... 4 | #include // gestisce tipo bool (per variabili booleane) 5 | #include // permette di usare la funzione assert 6 | #include // funzioni di confronto/copia/etc di stringhe 7 | #include // richiesto per usare errno 8 | 9 | // Scopo del programma: 10 | // mostrare le operazioni sui bit in C 11 | 12 | static void termina(const char *messaggio); 13 | 14 | 15 | #if 0 16 | && || And e Or logici 17 | 18 | a=2 19 | b=9 20 | a && b -> true 21 | 22 | 23 | ----- 24 | & | ^ bitwise operazioni tra i bit degli interi 25 | 26 | a =00000011 27 | b =00001001 28 | 29 | a&b -> 00000001 30 | a|b -> 00001011 31 | a^b => 00001010 32 | 33 | esiste anche il ~ (not bitwise) 34 | ~a = 11111100 35 | 36 | 37 | << shift sin 38 | >> shift dex 39 | 40 | b = 00001001 41 | 42 | c = b<<3 -> 01001000 43 | c>>2 -> 00010010 44 | 45 | In C lo shift destro può essere aritmetico o logico 46 | il comportamento è implementation dependent 47 | d = 110000....1 48 | d>>2 49 | possiamo ottenere 00110000.... 50 | ma anche 1111000000 51 | e = 001000....1 (il bit più significavo è 0) 52 | e>>2 ottengo sempre 00001000... 53 | #endif 54 | 55 | 56 | // converte il primo intero passato sulla linea di comando in binario 57 | // e il secondo da binario a decimale 58 | int main(int argc, char *argv[]) 59 | { 60 | // verifica siano stati fornito un parametro 61 | if(argc!=3) { 62 | printf("Uso: %s intero stringa01\n",argv[0]); 63 | return 1; 64 | } 65 | int n = atoi(argv[1]); 66 | 67 | for(int i=31;i>=0;i--) { 68 | int mask = 1<31) 78 | termina("Stringa in input troppo lunga"); 79 | for(int i=0;i // permette di usare scanf printf etc ... 3 | #include // conversioni stringa exit() etc ... 4 | #include // gestisce tipo bool 5 | #include // permette di usare la funzione ass 6 | #include // funzioni per stringhe 7 | #include // richiesto per usare errno 8 | 9 | 10 | // inverti file 11 | // legge tutte le linee da un file di testo e le 12 | // stampa su stdout in ordine inverso 13 | 14 | // utilizza il tipo stringola: legge definizione e prototipi 15 | #include "listastringhe.h" 16 | 17 | 18 | // prototipi delle funzioni che appaiono dopo il main() 19 | void termina(const char *messaggio); 20 | 21 | 22 | int main(int argc, char *argv[]) 23 | { 24 | 25 | if(argc!=2) { 26 | printf("Uso: %s nomefile\n",argv[0]); 27 | exit(1); 28 | } 29 | FILE *f = fopen(argv[1],"r"); 30 | if(f==NULL) termina("Errore apertura file input"); 31 | 32 | // costruzione lista leggendo le linee dal file 33 | stringola *linee=NULL; 34 | // ciclo di lettura dal file 35 | size_t n=0; 36 | char *buffer=NULL; 37 | while(true) { 38 | ssize_t e = getline(&buffer,&n,f); 39 | if(e<0) break; 40 | // crea stringa con linea del file 41 | if(buffer[strlen(buffer)-1] == '\n') 42 | buffer[strlen(buffer)-1] = '\0'; 43 | stringola *s = stringola_crea(buffer); 44 | // aggiunge in testa alla lista 45 | s->next = linee; 46 | linee = s; 47 | } 48 | free(buffer); 49 | if(fclose(f)!=0) termina("Errore chiusura file"); 50 | lista_stringola_stampa(linee,stdout); 51 | // dealloco la lista e termino 52 | lista_stringola_distruggi(linee); 53 | return 0; 54 | } 55 | 56 | 57 | // stampa su stderr il messaggio che gli passo 58 | // se errno!=0 stampa anche il messaggio d'errore associato 59 | // a errno. dopo queste stampe termina il programma 60 | void termina(const char *messaggio) 61 | { 62 | if(errno==0) 63 | fprintf(stderr,"%s\n",messaggio); 64 | else 65 | perror(messaggio); 66 | exit(1); 67 | } 68 | -------------------------------------------------------------------------------- /03makefile/leggi_bin.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE // avverte che usiamo le estensioni GNU 2 | #include // permette di usare scanf printf etc ... 3 | #include // conversioni stringa/numero exit() etc ... 4 | #include // gestisce tipo bool (per variabili booleane) 5 | #include // permette di usare la funzione assert 6 | #include // funzioni di confronto/copia/etc di stringhe 7 | #include // richiesto per usare errno 8 | 9 | // Scopo del programma: 10 | // mostrare come calcolare la dimensione di un file 11 | // e come si legge da un file binario 12 | 13 | 14 | static void termina(const char *messaggio); 15 | 16 | 17 | int main(int argc, char *argv[]) 18 | { 19 | // verifica siano stati forniti esattamente 2 parametri 20 | if(argc!=2) { 21 | printf("Uso: %s nome_file\n",argv[0]); 22 | return 1; 23 | } 24 | char *nome_file = argv[1]; 25 | 26 | // apro il file in lettura 27 | FILE *f = fopen(nome_file,"rb"); 28 | if(f==NULL) termina("Apertura file fallita"); 29 | 30 | // leggo tutti gli interi del file e li metto in un array 31 | 32 | // determino la dimensione del file 33 | // per farlo mi metto alla fine del file 34 | int e = fseek(f, 0, SEEK_END); 35 | if(e!=0) termina("Errore fseek"); 36 | // chiedo in che posizione del file sono 37 | long lungfile = ftell(f); 38 | if(lungfile<0) termina("Errore ftell"); 39 | if(lungfile%4!=0) termina("Il file non contiene int32"); 40 | // numero di interi nel file 41 | int n = lungfile/4; 42 | if(n==0) termina("file vuoto"); 43 | // alloca array dove mettere gli interi 44 | int *a = malloc(n*sizeof(*a)); 45 | if(a==NULL) termina("errore malloc"); 46 | rewind(f); // "riavvolgo" il file 47 | // leggo tutti gli interi nell'array a[] 48 | size_t m = fread(a,sizeof(int),n,f); 49 | if(n!=m) termina("errore fread"); 50 | // chiudi il file 51 | if(fclose(f)==EOF) 52 | termina("Errore chiusura file");; 53 | // stampiamo gli interi letti 54 | for(int i=0;i // permette di usare scanf printf etc ... 3 | #include // conversioni stringa exit() etc ... 4 | #include // gestisce tipo bool 5 | #include // permette di usare la funzione ass 6 | #include // funzioni per stringhe 7 | #include // richiesto per usare errno 8 | 9 | void termina(const char *messaggio); 10 | 11 | #include "listastringhe.h" 12 | 13 | // "elimina" gli spazi in testa a una stringa 14 | // restituisce un puntatore alla prima posizione 15 | // che non è uno spazio 16 | char *elimina_spazi_testa(char s[]) 17 | { 18 | int i=0; 19 | while(s[i]==' ') 20 | i++; 21 | assert(s[i]!=' '); 22 | return &s[i]; 23 | } 24 | 25 | 26 | // main che legge le linee e le spezza al ; 27 | // poi inserisce le stringhe in una lista ordinata 28 | int main(int argc, char *argv[]) 29 | { 30 | 31 | if(argc!=2) { 32 | printf("Uso: %s nomefile\n",argv[0]); 33 | exit(1); 34 | } 35 | FILE *f = fopen(argv[1],"r"); 36 | if(f==NULL) termina("Errore apertura file"); 37 | 38 | // costruzione lista stringhe leggendo dal file 39 | // ogni linea del file puo' contenere piu' stringhe 40 | // le stringhe posso contentenere degli spazi 41 | stringola *lista=NULL; // lista vuota 42 | // ciclo di lettura dal file f 43 | char *buffer=NULL; // usate da getline() 44 | size_t n=0; 45 | while(true) { 46 | //leggi linea dal file 47 | ssize_t e = getline(&buffer,&n,f); 48 | if(e<0) { // assumiamo sia finito il file 49 | free(buffer); // dealloco il buffer usate per contenere le linee 50 | break; 51 | } 52 | // fprintf(stderr,"n=%zd, buffer=%s",n,buffer); 53 | // esegue il parsing di buffer 54 | char *s = strtok(buffer,";\n"); 55 | while(s!=NULL) { 56 | s = elimina_spazi_testa(s); 57 | if(s[0]!='\0') { 58 | stringola *c = stringola_crea(s); 59 | // aggiungo la stringa alla lista 60 | lista = lista_stringola_inserisci_lex(lista,c); 61 | } 62 | s = strtok(NULL,";\n"); 63 | } 64 | // ho messo tutte le stringhe date da strtok 65 | } // end while del getline 66 | fclose(f); 67 | lista_stringola_stampa(lista,stdout); 68 | lista_stringola_distruggi(lista); 69 | return 0; 70 | } 71 | 72 | 73 | 74 | 75 | // stampa su stderr il messaggio che gli passo 76 | // se errno!=0 stampa anche il messaggio d'errore associato 77 | // a errno. dopo queste stampe termina il programma 78 | void termina(const char *messaggio) 79 | { 80 | if(errno==0) 81 | fprintf(stderr,"%s\n",messaggio); 82 | else 83 | perror(messaggio); 84 | exit(1); 85 | } 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /03makefile/listastringhe.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE // avverte che usiamo le estensioni GNU 2 | #include // permette di usare scanf printf etc ... 3 | #include // conversioni stringa exit() etc ... 4 | #include // gestisce tipo bool 5 | #include // permette di usare la funzione ass 6 | #include // funzioni per stringhe 7 | #include // richiesto per usare errno 8 | 9 | #include "listastringhe.h" 10 | 11 | 12 | stringola *stringola_crea(char *s) 13 | { 14 | stringola *a = malloc(sizeof(*a)); 15 | a->str = strdup(s); // creo una copia di s e l'assegno al nome 16 | a->next = NULL; 17 | return a; 18 | } 19 | 20 | void stringola_distruggi(stringola *a) 21 | { 22 | free(a->str); 23 | free(a); 24 | } 25 | 26 | void stringola_stampa(stringola *a, FILE *f) { 27 | fprintf(f,"%-20s\n",a->str); 28 | } 29 | 30 | void lista_stringola_stampa(stringola *lis, FILE *f) 31 | { 32 | while(lis!=NULL) { 33 | stringola_stampa(lis,f); 34 | lis = lis->next; 35 | } 36 | } 37 | 38 | void lista_stringola_distruggi(stringola *lis) 39 | { 40 | if(lis!=NULL) { 41 | lista_stringola_distruggi(lis->next); 42 | stringola_distruggi(lis); 43 | } 44 | } 45 | 46 | // input lis: lista di stringole può essere vuota 47 | // ma deve essere ordinata lessicograficamente 48 | // c: stringola da inserire deve eiustere c!=NULL 49 | // output la nuova lsta con c inserita matenemdo l'ordine 50 | stringola *lista_stringola_inserisci_lex(stringola *lis, stringola *c) 51 | { 52 | assert(c!=NULL); 53 | if(lis==NULL) { 54 | c->next = NULL; 55 | return c; 56 | } 57 | if(strcmp(c->str,lis->str)<0) { 58 | // il nome in c è il più piccolo 59 | // diventa lui il primo elemento 60 | c->next = lis; 61 | return c; 62 | } 63 | else { 64 | // lis rimane il primo elemento, quindi restituisco lui 65 | // seguito dal resto della lista in cui la ricorsione 66 | // ha piazzato c al posto giusto 67 | lis->next = lista_stringola_inserisci_lex(lis->next,c); 68 | return lis; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /03makefile/listastringhe.h: -------------------------------------------------------------------------------- 1 | 2 | // definzione struct che rappresenta una stringa 3 | typedef struct stringola { 4 | char *str; 5 | struct stringola *next; 6 | } stringola; 7 | 8 | stringola *stringola_crea(char *s); 9 | void stringola_distruggi(stringola *a); 10 | void stringola_stampa(stringola *a, FILE *f); 11 | void lista_stringola_stampa(stringola *lis, FILE *f); 12 | void lista_stringola_distruggi(stringola *lis); 13 | stringola *lista_stringola_inserisci_lex(stringola *lis, stringola *c); 14 | 15 | -------------------------------------------------------------------------------- /03makefile/makefile: -------------------------------------------------------------------------------- 1 | # definizione del compilatore e dei flag di compilazione 2 | # che vengono usate dalle regole implicite 3 | CC=gcc 4 | CFLAGS=-std=c11 -Wall -g 5 | LDLIBS=-lm 6 | 7 | 8 | # su https://www.gnu.org/software/make/manual/make.html#Implicit-Rules 9 | # sono elencate le regole implicite (non tutte) e le variabili 10 | # usate dalle regole implicite 11 | 12 | # Variabili automatiche: https://www.gnu.org/software/make/manual/make.html#Automatic-Variables 13 | # nei comandi associati ad ogni regola: 14 | # $@ viene sostituito con il nome del target 15 | # $< viene sostituito con il primo prerequisito 16 | # $^ viene sostituito con tutti i prerequisiti 17 | 18 | # elenco degli eseguibili da creare 19 | EXECS=legginomi invertifile qsortint qsortstr matrice bitops scrivi_primi_bin leggi_bin 20 | 21 | # primo target: gli eseguibili sono precondizioni 22 | # quindi verranno tutti creati 23 | all: $(EXECS) 24 | 25 | 26 | 27 | # creazione eseguibile legginomi 28 | # i comandi di compilazione sono dati in 29 | # maniera esplicita (di solito non si fa) 30 | 31 | # primo file ogggetto 32 | listastringhe.o: listastringhe.c listastringhe.h 33 | gcc -std=c11 -Wall -g -c listastringhe.c 34 | # secondo file oggetto 35 | legginomi.o: legginomi.c listastringhe.h 36 | gcc -std=c11 -Wall -g -c legginomi.c 37 | # file eseguibile 38 | legginomi: legginomi.o listastringhe.o 39 | gcc legginomi.o listastringhe.o -o legginomi 40 | 41 | # creazione dell'eseguibile invertifile 42 | 43 | # i comandi usano le variabili automatiche (molto piu semplice) 44 | invertifile.o: invertifile.c listastringhe.h 45 | $(CC) $(CFLAGS) -c $< 46 | 47 | # qui uso $@ per indicare il target (listcitta) 48 | invertifile: invertifile.o listastringhe.o 49 | $(CC) $^ $(LDLIBS) -o $@ 50 | 51 | # gli altri eseguibili sono creati con regole implicite 52 | # perché non necessitano dei file oggetto 53 | 54 | 55 | # esempio di target che non corrisponde a una compilazione 56 | # ma esegue la cancellazione dei file oggetto e degli eseguibili 57 | clean: 58 | rm *.o $(EXECS) 59 | -------------------------------------------------------------------------------- /03makefile/matrice.c: -------------------------------------------------------------------------------- 1 | /* ********************************************************* 2 | * dimostrazione di uso degli array bidimensionali 3 | * sia statici che dinamici 4 | * ********************************************************* */ 5 | #include // permette di usare scanf printf etc ... 6 | #include // conversioni stringa/numero rand() abs() exit() 7 | #include // gestisce tipo bool (per variabili booleane) 8 | #include // permette di usare la funzione assert 9 | #include // prototipi delle funzioni per stringhe 10 | 11 | // prototipi 12 | void termina(const char *messaggio); 13 | void stampa_matrice(int r, int c, int q[][c], FILE *f); 14 | void stampa_matrice_dinamica(int r, int c, int **q, FILE *f); 15 | int **crea_matrice_interi(int r, int c); 16 | 17 | 18 | int main(int argc, char *argv[]) 19 | { 20 | if(argc!=3) { 21 | fprintf(stderr,"Uso: %s righe colonne\n",argv[0]); 22 | exit(EXIT_FAILURE); 23 | } 24 | // legge il numero di righe e colonne dalla riga di comando 25 | int righe = atoi(argv[1]); 26 | int colonne = atoi(argv[2]); 27 | if(righe<1 || colonne <1) 28 | termina("Righe e colonne devono essere positive"); 29 | 30 | // matrice allocata staticamente 31 | int a[righe][colonne]; 32 | 33 | for(int i=0;i // permette di usare scanf printf etc ... 5 | #include // conversioni stringa/numero rand() abs() exit() etc ... 6 | #include // gestisce tipo bool (per variabili booleane) 7 | #include // permette di usare la funzione assert 8 | #include // richiesto per usare errno 9 | 10 | // stampa un messaggio di errore e termina 11 | void termina(const char *messaggio); 12 | 13 | 14 | // funzione di confronto, con i tipi corretti 15 | // necessita del casting al tipo __compar_fn_t 16 | // nella chiamata del qsort altrimenti il compilatore 17 | // da un warning 18 | int confronta(int *a, int *b) 19 | { 20 | if(*a<*b) return -1; 21 | else if(*a>*b) return 1; 22 | return 0; 23 | } 24 | 25 | // funzione di confronto che orfina mettendo prima tutti i pari 26 | // e successivamente tutti i dispari 27 | int confrontapd(int *a, int *b) 28 | { 29 | // i pari prima dei dispari 30 | if(*a%2==0 && *b%2!=0) return -1; 31 | if(*a%2!=0 && *b%2==0) return 1; 32 | // ora dovrebbero esere entrambi pari o entrambi dispari 33 | assert( (*a%2==0 && *b%2==0) || 34 | (*a%2!=0 && *b%2!=0)); 35 | // ordinamento in ordine crescente 36 | if(*a<*b) return -1; 37 | else if(*a>*b) return 1; 38 | return 0; 39 | } 40 | 41 | // funzione di confronto con i tipi 42 | // esatti del prototipo di qsort() 43 | int confronta_void(const void *a, const void *b) 44 | { 45 | int *aa = (int *) a; 46 | int *bb = (int *) b; 47 | 48 | // ordinamento in ordine crescente 49 | if(*aa<*bb) return -1; 50 | else if(*aa>*bb) return 1; 51 | 52 | return 0; 53 | } 54 | 55 | 56 | 57 | 58 | int main(int argc, char *argv[]) 59 | { 60 | if(argc<=2) { // input sulla linea di comando non corretto 61 | printf("Uso: %s i1 i2 i3 ... ik \n",argv[0]); 62 | return 1; 63 | } 64 | int n = argc-1; // Numero argomenti linea di comando 65 | 66 | // alloco array dinamico 67 | int *a = malloc(n*sizeof(int)); 68 | if(a==NULL) termina("Memoria insufficiente"); 69 | // riempio con interi passati sulla linea di comando 70 | for(int i=0;i // permette di usare scanf printf etc ... 5 | #include // conversioni stringa/numero rand() abs() exit() etc ... 6 | #include // gestisce tipo bool (per variabili booleane) 7 | #include // permette di usare la funzione assert 8 | #include // richiesto per usare errno 9 | #include 10 | 11 | // stampa un messaggio di errore e termina 12 | void termina(const char *messaggio); 13 | 14 | 15 | // funzione di confronto, con i tipi corretti 16 | // necessita del casting al tipo __compar_fn_t 17 | // nella chiamata del qsort altrimenti il compilatore 18 | // da un warning 19 | int confronta_str(char **a, char **b) 20 | { 21 | return strcmp(*a,*b); 22 | } 23 | 24 | int main(int argc, char *argv[]) 25 | { 26 | if(argc<=2) { // input sulla linea di comando non corretto 27 | printf("Uso: %s str1 str2 str3 ... strk \n",argv[0]); 28 | return 1; 29 | } 30 | int n = argc-1; // Numero argomenti linea di comando 31 | 32 | char **a = &argv[1]; 33 | 34 | // stampo array 35 | for(int i=0;i // permette di usare scanf printf etc ... 3 | #include // conversioni stringa/numero exit() etc ... 4 | #include // gestisce tipo bool (per variabili booleane) 5 | #include // permette di usare la funzione assert 6 | #include // funzioni di confronto/copia/etc di stringhe 7 | #include // richiesto per usare errno 8 | 9 | // Scopo del programma: 10 | // mostrare come si crea un file binario 11 | // in questo esempio viene scritto un intero alla volta 12 | // ma se ho un array posso scriverlo con una singola fwrite 13 | 14 | static void termina(const char *messaggio); 15 | 16 | 17 | // dato k restituisco true se è primo, false altrimenti 18 | bool primo(int k) 19 | { 20 | assert(k>0); 21 | if(k%2==0) 22 | return k==2; // se k è pari allora è primo se e solo se k==2 23 | 24 | // mi occupo ora del caso k dispari 25 | assert(k%2!=0); 26 | for(int i=3; ik) break; 29 | } 30 | return true; 31 | } 32 | 33 | 34 | 35 | int main(int argc, char *argv[]) 36 | { 37 | // verifica siano stati forniti esattamente 2 parametri 38 | if(argc!=3) { 39 | printf("Uso: %s N nome_file\n",argv[0]); 40 | return 1; 41 | } 42 | // converte il primo parametro in un intero 43 | int n = atoi(argv[1]); 44 | if(n<=0) termina("Il parametro n deve essere positivo"); 45 | // copia il puntatore nella variabile nome_file 46 | char *nome_file = argv[2]; 47 | 48 | // apro il file in scrittura 49 | FILE *f = fopen(nome_file,"wb"); 50 | if(f==NULL) termina("Apertura file fallita"); 51 | 52 | // cerca i primi da 2 a n e li scrive dentro il file 53 | for(int i=2;i<=n;i++) 54 | if(primo(i)) { 55 | // scrittora dell'intero i in formato binario 56 | int e = fwrite(&i,sizeof(i),1,f); 57 | if(e!=1) termina("Errore nella scrittura"); 58 | } 59 | // se io avessi messo i primi in un array 60 | // a[0...k-1], li scrivevo in f con l'istruzione 61 | // fwrite(a,sizeof(*a),k,f); 62 | 63 | // chiudi il file e termina 64 | if(fclose(f)==EOF) 65 | termina("Errore chiusura file");; 66 | 67 | return 0; 68 | } 69 | 70 | 71 | // stampa su stderr il messaggio che gli passo 72 | // se errno!=0 stampa anche il messaggio d'errore associato 73 | // a errno. dopo queste stampe termina il programma 74 | static void termina(const char *messaggio) 75 | { 76 | if(errno==0) 77 | fprintf(stderr,"%s\n",messaggio); 78 | else 79 | perror(messaggio); 80 | exit(1); 81 | } 82 | -------------------------------------------------------------------------------- /04assembler/Readme.md: -------------------------------------------------------------------------------- 1 | ### Utilizzo di un Raspberry Pi per programmare in assembler ARM 2 | 3 | 4 | 1. Installare sul Raspberry il sistema operativo [Raspberry Pi OS](https://www.raspberrypi.com/software/): ho provato anche Ubuntu server ma, oltre ad essere più lento, i programmi non venivano compilati correttamente. Per l'accesso e lo scambio di file con il Raspberry è necessario utilizzare `ssh` seguendo [questa guida](https://www.raspberrypi.com/documentation/computers/remote-access.html). 5 | 6 | 7 | 2. Installare *valgrind* con `sudo apt install valgrind`. Se la versione di *valgrind* è precedente alla 3.17 e segnala errori inesistenti, installate l'ultima versione dal [sito ufficiale](https://valgrind.org/downloads/current.html) seguendo le istruzioni del README. 8 | 9 | 10 | 3. Non ho trovato IDE già configurati per l'assembler ARM; io utilizzo [Geany](https://geany.org/) (solitamente è già istallato) al quale ho aggiunto qualche configurazione specifica per l'assembler. In particolare il file *filetypes.asm* contiene la configurazione per l'highlight delle principali parole chiave e per associare ai tasti F8/F9/shift-F9 i comandi Compile/Build/Make. Andando su *Build->Set build commands* potete ridefinire questi comandi (eventualmente per eseguire la cross compilation). Il file *filetypes.asm* va messo nella directory *~/.config/geany/filedefs*. Il file *bespin2.conf* contiene un tema dark ed è da mettere nella directory *~/.config/geany/colorschemes*. Purtroppo non sono riuscito a fargli capire che i commenti iniziano con `@` e non con `;` per rimediare a questo inizio i commenti con i due caratteri `@;` 11 | 12 | 4. Per testare la compilazione potete usare il file `primi.c` che calcola una tabella di primi utilizzando un test di primalità definito all'interno del file `primo.s`. L'eseguibile viene creato dando il comando `make primi` 13 | 14 | 15 | 5. Se volete utilizzare `gdbgui` come debugger come visto a lezione dovete installarlo con il comando `pip install gdbgui` come descritto sulla [guida ufficiale](https://www.gdbgui.com/). 16 | 17 | 18 | 19 | ### Per chi non ha un Raspberry... 20 | 21 | In questo caso per testare i programmi in assembler dovete usare il procedimento di cross-compilazione indicato nelle dispense di AESO. Nel `makefile` allegato trovate (commentate) le definizioni delle variabili `CC` e `CFLAGS` necessarie per la cross-compilazione sulla macchina `laboratorio2`. Dopo la compilazione per eseguire i programmi dovete precederli da `qemu-arm`, ad esempio `qemu-arm primi 40`. Per il debugging dei programmi in arm su `laboratorio2` dovete usare `gdb-multiarch` (gdbgui non funziona) e non potete usare `valgrind`. 22 | 23 | -------------------------------------------------------------------------------- /04assembler/bespin2.conf: -------------------------------------------------------------------------------- 1 | # 2 | # This file was generated from a textmate theme named Bespin 3 | # with tm2gtksw2 tool. (Alexandre da Silva) 4 | 5 | # This library is free software; you can redistribute it and/or 6 | # modify it under the terms of the GNU Library General Public 7 | # License as published by the Free Software Foundation; either 8 | # version 2 of the License, or (at your option) any later version. 9 | 10 | # This library is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # Library General Public License for more details. 14 | 15 | # You should have received a copy of the GNU Library General Public 16 | # License along with this library; if not, write to the 17 | # Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 | # Boston, MA 02111-1307, USA. 19 | # 20 | # Ported to Geany by Matthew Brush 21 | # 22 | 23 | [theme_info] 24 | name=Bespin 2.0 25 | description=A port of the Bespin theme. 26 | # incremented automatically, do not change manually 27 | version=1225 28 | author=Alexandre da Silva (tm2gtksw2) 29 | url=https://github.com/gmate/gmate/blob/master/styles/Bespin.xml 30 | # list of each compatible Geany release version 31 | compat=1.22;1.23;1.23.1;1.24 32 | 33 | [named_styles] 34 | 35 | default=#eee;#28211c;false;false 36 | error=#f8f8f8;#4a2947 37 | 38 | # Editor styles 39 | #------------------------------------------------------------------------------- 40 | 41 | selection=#baae9e;#4c4a49;true;true 42 | current_line=#000;#2e2723;true 43 | brace_good=#00f;#2e2723;true;false 44 | brace_bad=#df4545;#2e2723;true;false 45 | margin_line_number=#baae9e;#2e2723 46 | margin_folding=#baae9e;#2e2723 47 | fold_symbol_highlight=#2e2723 48 | indent_guide=#40342c 49 | white_space=#40342c;#fff;true;false 50 | caret=#a7a7a7;#000;false 51 | marker_line=#000;#ff0; 52 | marker_search=#000;#0000f0; 53 | marker_mark=#000;#b8f4b8; 54 | call_tips=#c0c0c0;#fff;false;false 55 | 56 | # Programming languages 57 | #------------------------------------------------------------------------------- 58 | 59 | comment=#cec;;;true 60 | comment_doc=comment 61 | comment_line=comment 62 | comment_line_doc=comment_doc 63 | comment_doc_keyword=comment_doc,bold 64 | comment_doc_keyword_error=comment_doc,italic 65 | 66 | number=#cf6a4c 67 | number_1=number 68 | number_2=number_1 69 | 70 | type=#9b859d;;true 71 | class=type 72 | function=#937121 73 | parameter=function 74 | 75 | keyword=#5ea6ea;;true 76 | keyword_1=keyword 77 | keyword_2=type 78 | keyword_3=keyword_1 79 | keyword_4=keyword_1 80 | 81 | identifier=default 82 | identifier_1=identifier 83 | identifier_2=identifier_1 84 | identifier_3=identifier_1 85 | identifier_4=identifier_1 86 | 87 | string=#54be0d 88 | string_1=string 89 | string_2=string_1 90 | string_3=default 91 | string_4=default 92 | string_eol=string_1,italic 93 | character=string_1 94 | backticks=string_2 95 | here_doc=string_2 96 | 97 | scalar=string_2 98 | label=default,bold 99 | preprocessor=#cf6a4c 100 | regex=#e9c062 101 | operator=#C0E0FF 102 | decorator=string_1,bold 103 | other=#ddf2a4 104 | 105 | # Markup-type languages 106 | #------------------------------------------------------------------------------- 107 | 108 | tag=#ac885b 109 | tag_unknown=#ac885b 110 | tag_end=#ac885b 111 | attribute=#937121 112 | attribute_unknown=#937121 113 | value=string_1 114 | entity=default 115 | 116 | # Diff 117 | #------------------------------------------------------------------------------- 118 | 119 | line_added=#f8f8f8;#253b22 120 | line_removed=#f8f8f8;#420e09 121 | line_changed=#f8f8f8;#4a410d 122 | -------------------------------------------------------------------------------- /04assembler/filetypes.asm: -------------------------------------------------------------------------------- 1 | [build-menu] 2 | FT_01_LB=Build 3 | FT_01_CM=gcc -g "%f" -o "%e" 4 | FT_01_WD= 5 | FT_00_LB=_Compile 6 | FT_00_CM=gcc -g -c "%f" 7 | FT_00_WD= 8 | 9 | FT_02_LB= 10 | FT_02_CM= 11 | FT_02_WD= 12 | 13 | [settings] 14 | # per qualche motivo questo non funziona 15 | comment_single=@ 16 | 17 | [indentation] 18 | width=4 19 | # 0 is spaces, 1 is tabs, 2 is tab & spaces 20 | type=0 21 | 22 | 23 | [keywords] 24 | # all items must be in one line 25 | instructions=add and asr b bic bl bx cmp eor ldmdb ldmfd ldr ldrb lsl lsr mls mov mul mvn orr pop ror rrx sdiv smull stmfd str strb sub svc tst udiv umull vadd vcvt vldr vmov vstr push beq bne bpl bhs blo bhi bge ble bgt blt ldreq ldrne streq strne strlt moveq movne movlt subne subeq sublt 26 | registers=r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 sp lr pc 27 | directives=.text .data .global .byte .hword .word .string .code .if .else .endif .req .equ .section .type 28 | 29 | -------------------------------------------------------------------------------- /04assembler/makefile: -------------------------------------------------------------------------------- 1 | # compilatore e flag per macchine arm7 2 | CFLAGS=-std=c11 -g -Wall 3 | CC=gcc 4 | # compilatore e flag per cross-compilazione 5 | # CFLAGS=-std=c11 -g -Wall -static 6 | # CC=arm-linux-gnueabihf-gcc 7 | 8 | # eseguibili che si vogliono creare 9 | EXECS=primi strcmp tokC tok 10 | 11 | all: $(EXECS) 12 | 13 | 14 | # stampa elenco dei primi <=N 15 | primi: primi.c primo.s 16 | $(CC) $(CFLAGS) $^ -o primi 17 | 18 | 19 | # funzioni di tokenizzazione in C 20 | tokC: tok.c 21 | $(CC) $(CFLAGS) $^ -o $@ -DNOARM 22 | 23 | 24 | # pattern rule valida per tutti gli eseguibili ottenibili 25 | # da un .c e un .s con lo stesso nome ad esempio strcmp.c strcmp.s 26 | # la ricetta per ottenere il target è la stessa in quanto espressa 27 | # in termini delle variabili speciali $ e $@ 28 | %: %.c %.s 29 | $(CC) $(CFLAGS) $^ -o $@ 30 | 31 | 32 | # regola per cancellare tutti gli eseguibili e i file oggetto 33 | # serve se voglio rifare tutta la compilazione da capo 34 | # per eseguirla si deve scrivere `make clean` sulla linea di comando 35 | clean: 36 | rm -f $(EXECS) *.o 37 | -------------------------------------------------------------------------------- /04assembler/primi.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE // avverte che usiamo le estensioni GNU 2 | #include // permette di usare scanf printf etc ... 3 | #include // conversioni stringa/numero exit() etc ... 4 | #include // gestisce tipo bool (per variabili booleane) 5 | #include // permette di usare la funzione assert 6 | #include // funzioni di confronto/copia/etc di stringhe 7 | 8 | // le istruzioni qui sopra le spieghiamo più avanti 9 | 10 | void termina(char *messaggio) 11 | { 12 | puts(messaggio); 13 | exit(1); 14 | } 15 | 16 | 17 | // dato k restituisco !=0 se e' primo, 0 altrimenti 18 | // realizzata in primi.s 19 | int primo(int k); 20 | 21 | 22 | 23 | // legge un intero N e costruisce array dei primi <=N 24 | int main(int argc, char *argv[]) 25 | { 26 | int n; 27 | 28 | if(argc!=2) { 29 | printf("Uso: %s nmax\n",argv[0]); 30 | return 1; 31 | } 32 | n = atoi(argv[1]); 33 | if(n<2) 34 | termina("L'array che ti interesa è vuoto"); 35 | 36 | int *a; // array che conterrà i primi 37 | int size=10; // dimensione attuale dell'array 38 | int messi=0; // numero di eleemnti attulamente nell'array 39 | a = malloc(size*sizeof(int)); 40 | if(a==NULL) 41 | termina("Memoria insufficiente"); 42 | 43 | // cerco i numeri primi da 2 a N 44 | for(int i=2;i<=n;i++) { 45 | // se i è primo lo aggiungo ad a[] 46 | if(primo(i)) { 47 | // devo aggungere i all'array a[] 48 | if(messi==size) { 49 | // ingrandisco l'array 50 | size = size*2; 51 | a = realloc(a,size*sizeof(int)); 52 | if(a==NULL) 53 | termina("realloc fallita"); 54 | } 55 | a[messi] = i; 56 | messi += 1; 57 | } 58 | } 59 | // ho messo tutti gli elementi che mi interesavano 60 | size = messi; 61 | a = realloc(a,size*sizeof(int)); 62 | if(a==NULL) 63 | termina("realloc fallita"); 64 | 65 | // stampo il contenuto dell'array 66 | for(int i=0;i1 2 | @; output: r0=0 se composto, l'input se è primo 3 | 4 | .data 5 | errmsg: .string "Input non valido (primo)" 6 | 7 | .text 8 | .global primo @; rende il simbolo primo visibile da altri file 9 | .type primo, %function @; necessario per qemu-arm 10 | 11 | primo: cmp r0, #2 @; calcola r0-2 12 | blt stop @; r0<2 errore 13 | bne not2 @; se r0!=2 continua 14 | mov pc, lr @; altrimenti return 2 15 | not2: and r1, r0, #1 @; r1 = r0 && 1 = r0%2 16 | cmp r1, #0 @; r0 e' pari? 17 | bne odd @; se r0 e' dispari continua 18 | nonpr: mov r0, #0 19 | end: mov pc,lr @; return 0 20 | odd: mov r1, #3 @; for(r1=3;r1*r1 <= r0; r1 +=2) 21 | loop: mul r3,r1,r1 22 | cmp r3,r0 @; se r1*r1 > r0 23 | bhi end @; return r0 24 | @; calcolo resto r3 = r0% r1 per sottrazioni successive (inefficiente) 25 | mov r3, r0 26 | resto1: cmp r3,r1 27 | blo resto2 @; is r3 // permette di usare scanf printf etc ... 3 | #include // conversioni stringa/numero exit() etc ... 4 | #include // gestisce tipo bool (per variabili booleane) 5 | #include // permette di usare la funzione assert 6 | #include // funzioni di confronto/copia/etc di stringhe 7 | #include 8 | 9 | 10 | // stampa un messaggio d'errore e termina il programma 11 | void termina(const char *messaggio); 12 | 13 | // strcmp implemetato in arm 14 | int armcmp(const char *,const char *); 15 | 16 | 17 | // confronta argomenti passati sulla linea di comando 18 | int main(int argc, char *argv[]) 19 | { 20 | if(argc<=2) { 21 | printf("Uso:\t %s s1 s2 [s3 s4 ...]\n",argv[0]); 22 | return 1; 23 | } 24 | for(int i=1;i strcmp: %d\n",argv[i],argv[i+1],strcmp(argv[i],argv[i+1])); 26 | printf("%s vs %s --> armcmp: %d\n",argv[i],argv[i+1],armcmp(argv[i],argv[i+1])); 27 | } 28 | return 0; 29 | } 30 | 31 | 32 | int modello(char *s, char *t) 33 | { 34 | for(int i=0; ;i++) 35 | if(s[i]!=t[i]) 36 | return s[i]-t[i]; 37 | else if(s[i]==0) 38 | return 0; 39 | } 40 | 41 | 42 | 43 | void termina(const char *messaggio){ 44 | if(errno!=0) perror(messaggio); 45 | else fprintf(stderr,"%s\n", messaggio); 46 | exit(1); 47 | } 48 | 49 | 50 | -------------------------------------------------------------------------------- /04assembler/strcmp.s: -------------------------------------------------------------------------------- 1 | @; input: 2 | @; r0, r1: array caratteri 0-terminati 3 | @; output: 4 | @; r0: valore < > ==0 a seconda che la stringa r0 sia 5 | @; lessicograficamente minore maggiore o uguale a r1 6 | 7 | .data 8 | 9 | .text 10 | .global armcmp @; nome funzione chiamabile dall'esterno 11 | .type armcmp, %function @; dice all'assembler che armcmp è una funzione 12 | 13 | armcmp: 14 | cmp r0,#0 15 | moveq r0,#11 16 | beq exit @; r0==NULL exit(11) 17 | cmp r1,#0 18 | moveq r0,#12 19 | beq exit @; r1==NULL exit(12) 20 | mov r2,#0 @; for(i=0 ....) 21 | fori: 22 | ldrb r3,[r0,r2] @; r3 = r0[r2] 23 | ldrb r12,[r1,r2] @; r12 = r1[r2] 24 | cmp r3,r12 25 | subne r0,r3,r12 26 | movne pc,lr @; return r3-12=r0[r2]-r1[r2] 27 | cmp r3,#0 28 | moveq r0,#0 29 | moveq pc,lr @; return 0 30 | add r2,r2,#1 @; r2++ 31 | b fori 32 | 33 | -------------------------------------------------------------------------------- /04assembler/tok.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE // avverte che usiamo le estensioni GNU 2 | #include // permette di usare scanf printf etc ... 3 | #include // conversioni stringa/numero exit() etc ... 4 | #include // gestisce tipo bool (per variabili booleane) 5 | #include // permette di usare la funzione assert 6 | #include // funzioni di confronto/copia/etc di stringhe 7 | 8 | 9 | 10 | // emulazione della funzione strtok in assembler o in C 11 | char *miatok(char *s, int delim); 12 | 13 | 14 | // tokenizza la stringa passata in argv[1] 15 | int main(int argc, char *argv[]) 16 | { 17 | if(argc==2) { 18 | char *tok = miatok(argv[1],','); 19 | while(tok!=NULL) { 20 | puts(tok); 21 | tok = miatok(NULL,','); 22 | } 23 | // verifico che anche la successiva chiamata a miatok restituisca NULL 24 | assert(miatok(NULL,',')==NULL); 25 | } 26 | else 27 | printf("Uso: %s stringa\n",argv[0]); 28 | return 0; 29 | } 30 | 31 | #ifdef NOARM 32 | char *miatok(char *s, int d) 33 | { 34 | static char *ultimapos = NULL; 35 | 36 | if(d==0) termina("Separatore illegale"); 37 | // riprende tokenizzazione precedente 38 | if(s==NULL) 39 | s = ultimapos; 40 | if(s==NULL) 41 | return NULL; 42 | 43 | // la stringa contiene qualcosa 44 | // salto eventuali caratteri = d 45 | while(*s==d) 46 | s += 1; // avanzo nella stringa 47 | 48 | // ora c'è qualcosa diverso dal delimitatore 49 | assert(*s!=d); 50 | if(*s=='\0') { // sono in fondo alla stringa? 51 | ultimapos = NULL; // non fare altre chiamate su questa stringa 52 | return NULL; 53 | } 54 | assert(*s!='\0' && *s!=d); 55 | // c'è un token che inizia in s 56 | char *t = s; 57 | for( ;*t!=d; t++) 58 | if(*t=='\0') { // siamo arrivati a fine stringa 59 | ultimapos = NULL; 60 | return s; 61 | } 62 | // ho trovato un carattere uguale a d 63 | assert(*t == d); 64 | *t = '\0'; // sovrascrivo il delimitatore con \0 65 | ultimapos = t + 1; // puntatore a carattere dopo \0 66 | return s; 67 | } 68 | #endif 69 | 70 | 71 | -------------------------------------------------------------------------------- /04assembler/tok.s: -------------------------------------------------------------------------------- 1 | @; funzione analoga alla strtok() tranne che ammette un singolo 2 | @; delimitatore invece che una stringa di possibili delimitatori 3 | 4 | @; prototipo formato C: 5 | @; char *miatok(char *s, int delim); 6 | 7 | @; input: r0 = s, r1 = delimitatore 8 | @; output: r0 = pubtatore inzio next token o NULL se non ce ne sono 9 | @; salvo in statica dove dove riprendere la tokenizzazione 10 | @; l'intero 0 indica il valore NULL del C 11 | 12 | @; corrispondenza fra le variabili del miatok() in C 13 | @; e i registri: 14 | @; r0 -> s indirizzo stringa in output (viene modificato) 15 | @; r1 -> d delimitatore 16 | @; r2 -> &ultimapos indirizzo variabile per riprendere tokenizzazione 17 | @; r3 -> t puntatore ausialirio, per trovare la fine del token 18 | 19 | 20 | .data 21 | statica: 22 | .word 0 @; area di memoria dove viene salvato da 23 | @; dove riprendere la tokenizzazione 24 | @; oppure NULL se è il parsing è completato 25 | @; inizialmente è NULL perché non c'è un parsing in sospeso 26 | 27 | .text 28 | .global miatok 29 | .type miatok, %function 30 | 31 | miatok: 32 | cmp r1,#0 @; il delimitatore deve essere !=0 33 | moveq r0, #10 34 | beq exit @; if(r1=='\0') exit(10) 35 | 36 | @; metto in r2 l'indirizzo di statica 37 | @; e non lo modifico mai 38 | ldr r2,=statica @; r2 = &statica 39 | 40 | @; if r0==NULL carico l'ultima posizione 41 | cmp r0,#0 42 | ldreq r0,[r2] @; metto in r0 l'indirizzo memorizzato in statica 43 | @; (cioè recupero dove ero arrivato alla fine 44 | @; del token precedente) in C sarebbe r0 = *r2 45 | cmp r0,#0 @; se in statica c'era NULL nessun parsing in sospeso 46 | moveq pc,lr @; return NULL 47 | 48 | @; esegue il parsing da r0 in poi 49 | saltadelimitatore: 50 | ldrb r12,[r0] @; legge carattere dalla posizione r0, in C r12 = *((char *) r0) 51 | cmp r12,r1 @; salta caratteri fino a che non si incontra 52 | addeq r0,r0,#1 @; un carattere diverso da r1 (il delimitatore) 53 | beq saltadelimitatore 54 | 55 | @; ho trovato qualcosa != delimitatore 56 | cmp r12,#0 @; fine stringa? 57 | moveq r0,#0 58 | streq r0,[r2] @; metto NULL in statica, in C sarebbe *r2 = NULL 59 | moveq pc,lr @; return NULL 60 | 61 | @; trovato carattere diverso da fine stringa 62 | @; possiamo restituire un nuovo token 63 | @; in r0 ho l'indirizzo del primo carattere del token 64 | @; quindi non lo modifico 65 | mov r3,r0 @; uso r3 per avanzare nel token 66 | avanti: 67 | ldrb r12, [r3,#1]! @; r12 = *(++r3) (legge il prossimo carattere) 68 | cmp r12,#0 @; fine stringa? 69 | moveq r3,#0 @; scrivo NULL in statica 70 | streq r3,[r2] @; perché non ci sono altri token 71 | moveq pc,lr @; return r0 = inizio del token 72 | cmp r12,r1 @; se r12!=delimitatore 73 | bne avanti @; considero carattere successivo 74 | @; trovato delimitatore in [r3], il token è finito 75 | mov r1,#0 @; r1 non mi serve più e lo sovrascrivo 76 | strb r1,[r3] @; scrivo '\0' sopra il delimitatore 77 | add r3,r3,#1 @; r3++ puntatore a carattere dopo delimitatore 78 | str r3, [r2] @; salvo puntatore r3 in statica 79 | mov pc,lr @; return r0 (indirizzo del primo carattere del token) 80 | -------------------------------------------------------------------------------- /05python/PyvsC.md: -------------------------------------------------------------------------------- 1 | 2 | ## Python vs C 3 | 4 | 5 | La sintassi di Python è simile a quella del C tranne che per le sequenti semplificazioni 6 | 7 | * Non è richiesto il `;` alla fine di ogni linea 8 | * invece delle `{ }` i blocchi sono evidenziati mediante indentazione (attenti all'editor) e con il carattere `:` 9 | * Le parentesi `( )` nei test degli `if`/`while` non sono necessarie 10 | * `/` vs `//` per distinguere tra divisione e divisione intera. Per i commenti si usa il carattere `#` 11 | * non ci sono `++` e `--` 12 | * operatori logici si chiamano con il loro nome: `and`, `or`, `not` etc 13 | * Invece di `true`/`false`/`NULL` ci sono `True`/`False`/`None` 14 | 15 | 16 | Python è un linguaggio interpretato non compilato: molto più lento del C (fino a 100 volte); gli errori vengono segnalati a runtime con messaggi solitamente comprensibili. 17 | 18 | Altra differenza sostanziale è che le variabili non hanno tipo e non vanno dichiarate. 19 | 20 | Le stringhe sono immutabili e facili da usare. Non c'è il tipo carattere: un carattere è una stringa di lunghezza uno. 21 | 22 | Gli interi hanno precisione illimitata: ci pensa l'interprete ad usare un numero adeguato di byte per rappresentare tutte le cifre (fate la prova con il fattoriale) 23 | 24 | ## Strutture di controllo e iterazione 25 | 26 | * if/else/elif 27 | * while/continue/break, esiste un comando else per i cicli, non esiste do 28 | * for è basato sul concetto di range, simile al for-each di Java 29 | 30 | ## Definizione e invocazione di funzioni 31 | 32 | Esempio di funzione che dati due interi restituisce la somma e la stringa contenente la loro concatenazione. Non è una funzione molto sensata: serve per far vedere che è possibile restituire più di un oggetto anche di tipo diverso. 33 | 34 | ```python 35 | # definizione 36 | def fun(a,b): 37 | return a+b,str(a) +str(b) 38 | 39 | # invocazione funzione e stampa risultato 40 | s,p = fun(3,5) 41 | print(s,p) 42 | ``` 43 | ## Costruzione stampa e modifica di una lista 44 | ```python 45 | lista = [1,2,3,"ciao"] 46 | print(lista[2:]) # estrae gli elementi da lista[2] alla fine 47 | lista[2] = 5 48 | lista = lista + [34,40] 49 | lista.append(35) 50 | print(lista) 51 | ``` 52 | 53 | ### Esempi di iterazione su una lista usando il ciclo for 54 | ```python 55 | parole = ["casa","mare","sole"] 56 | for x in parole: 57 | print(x.upper()) 58 | x = "monti" 59 | print(parole) 60 | for i in range(len(parole)): 61 | print(parole[i].upper()) 62 | i = 7 63 | print(parole) 64 | 65 | ``` 66 | Nota: la parola chiave `in` si usa nei cicli for e per testare l'appartenenza. Verificatelo eseguendo lea seguenti istruzioni: 67 | ```python 68 | print(4 in [1,2,3]) 69 | print(4 in [2,4,8]) 70 | ``` 71 | 72 | 73 | ## Dizionari 74 | 75 | Sono equivalenti alle `map` di Java ma più semplici da usare 76 | 77 | ```python 78 | d = {"casa":3, "sole":4} 79 | d["mare"] = 5 80 | d["casa"] = 10 81 | print(d) 82 | for c in d: 83 | print("Alla chiave", c, "è associato il valore", d[c]) 84 | ``` 85 | 86 | ## Docstring 87 | 88 | Una stringa delimitata da tre virgolette `"""` nella riga immediatamente successiva alla definizione di una funzione di chiama *docstring* e forma un commento che l'interprete associa alla funzione. Viene mostrata con il comando *help* e da alcuni editor specifici per python. Ad esempio 89 | 90 | ```python 91 | def media(a,b): 92 | """Calcola la media artimetica""" 93 | return (a+b)/2 94 | 95 | help(media) 96 | Help on function media in module __main__: 97 | 98 | media(a, b) 99 | Calcola la media aritmetica 100 | ``` 101 | 102 | ## Esecuzione di programmi 103 | 104 | Inizialmente eseguiremo i programmi chiamando le funzioni all'interno dell'interprete python (prompt `>>>`). L'interprete ha il vantaggio che permette di testare le singole istruzioni e di vedere il contenuto delle variabili. 105 | 106 | Successivamente eseguiremo i programmi python dalla linea di comando del terminale (in questo caso vengono chiamati `script`). Per poterli eseguire dalla linea di comando è necessario che il file contenente il sorgente inizi con la linea 107 | ```python 108 | #!/usr/bin/env python3 109 | ``` 110 | e che il file venga reso eseguibile con il comando `chmod(1)` -------------------------------------------------------------------------------- /05python/PyvsC.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | 3 | # esempi fatti a lezione: premere Run per leggere il file 4 | # dentro l'interprete (tab Console) e sperimentare 5 | 6 | # tre modi diversi di delimitare una stringa 7 | s1 = "ciao 1" 8 | s2 = 'ciao 2' 9 | s3 = """ciao! 10 | sono una stringa come le altre ma contengo dei \\n al 11 | mio interno infatti sono chiamata stringa 'multiriga'""" 12 | 13 | # i caratteri che non sono usati come delimitatori 14 | # possono comparire dentro la stringa 15 | s4 = 'Zinédine Zidane detto "Zizou"' 16 | 17 | 18 | # stampa delle stringhe definite prima altrimenti non sarebbero visualizzate 19 | # notiamo che la print di default aggiunge uno \n dopo aver stampato 20 | print(s1) 21 | print(s2) 22 | print(s3) 23 | print(s4) 24 | print("---- fine stringhe----") 25 | 26 | 27 | # esempio di ricorsione, asserzione, if/else/elsif 28 | def fatt(n): 29 | """calcola il fattoriale""" 30 | 31 | assert n>=0, "Argomento non puo essere negativo" 32 | if n==0: 33 | return 1 34 | elif n==1: 35 | return 1 36 | elif n==2: 37 | return 2 38 | else: 39 | return n*fatt(n-1) 40 | 41 | 42 | # esempio ciclo while + else 43 | def primo(n): 44 | assert n>1, "argomento deve essere >1" 45 | d=2 46 | while d*d<=n: 47 | if n%d==0: 48 | print(f"Il numero {n} è divisibile per {d}") 49 | break 50 | d += 1 51 | else: 52 | print(f"Il numero {n} è primo") 53 | return 54 | 55 | 56 | # fattoriale senza ricorsione 57 | # avendo lo stesso nome sovrascrive la 58 | # precedente definizione di fatt() 59 | def fatt(n): 60 | assert n>=0, "Argomento non puo essere negativo" 61 | f = 1 62 | for i in range(2,n+1): 63 | f *= i 64 | return f 65 | 66 | 67 | # esempio di uso del ciclo for decrescente 68 | def contoallarovescia(n): 69 | """stampa i numeri da n a 0 70 | adando indietro di 1 alla volta""" 71 | 72 | tot = 0 73 | for i in range(n,-1,-1): 74 | print(i) 75 | tot +=i 76 | # due modi diversi per stampare la stessa informazione 77 | print( "fine, la somma è:", tot) 78 | print(f"fine, la somma è: {tot}") 79 | 80 | 81 | # esempio creazione e manipolazione lista 82 | def esempio_lista(): 83 | lista = [1,2,3,"ciao"] 84 | print(lista[2:]) # estrae gli elementi da lista[2] alla fine 85 | lista[2] = 5 86 | lista = lista + [34,40] 87 | lista.append(35) 88 | print(lista) 89 | 90 | # esempio for sugli elementi di una lista 91 | def esempio_for_lista(): 92 | parole = ["casa","mare","sole"] 93 | # prima versione senza usare un indice 94 | for x in parole: # itera tra gli elementi di parole 95 | print(x.upper()) 96 | print(parole) 97 | # seconda versione 98 | for i in range(len(parole)): # itera tra 0 e len(parole)-1 99 | print(parole[i].upper()) # questo non modifica parole[i] 100 | parole[i] = parole[i] + str(i) # qui invece parole[i] cambia 101 | print(parole) 102 | 103 | 104 | # la funzione main non ha particolari proprietà in python ... 105 | def main(n): 106 | print(f"Fattoriale di {n}: {fatt(n)}") 107 | 108 | 109 | # ma per analogia con il C spesso la usiamo 110 | # per far partire l'esecuzione del programma 111 | # ma deve essere fatto esplicitamente come qui sotto 112 | main(100) 113 | 114 | -------------------------------------------------------------------------------- /05python/grande.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Esempio di script per la navigazione del filesystem 4 | Legge sulla riga di comando il nome di una directory 5 | e restituisce il file più grande in essa contenuto 6 | incluse tutte le sottodirectory 7 | 8 | 9 | Funzioni di libreria per la gestione di file e directory 10 | 11 | os.getcwd() # restituisce directory corrente 12 | os.chdir(path) # cambia directory 13 | os.listdir(path) # elenca file (restituisce lista di stringhe) 14 | os.access(path) # verifica i permessi 15 | 16 | os.path.getsize(path) # dimensione file 17 | os.path.exists(path) # vero se il file/directory esiste 18 | os.path.isfile(path) # vero se regular file 19 | os.path.isdir(path) # vero se directory 20 | os.path.islink(path) # vero se symbolic link 21 | os.path.join(nome_dir,nome_file) # combina nome dir e file 22 | os.path.abspath(path) # restituisce path assoluto 23 | os.path.realpath(path) # restituisce nome canonico eliminando link simbolici 24 | 25 | Lista completa dei comandi su: 26 | https://docs.python.org/3/library/os.html 27 | https://docs.python.org/3/library/os.path.html 28 | 29 | Per informazioni sui permessi dei file o come 30 | cambiarli: `man chmod` 31 | 32 | Per informazioni sui link simbolici e il loro uso: 33 | https://linuxize.com/post/how-to-create-symbolic-links-in-linux-using-the-ln-command/ 34 | """ 35 | import os, os.path, sys 36 | 37 | 38 | def main(nomedir): 39 | """Lancia ricerca ricorsiva su nomedir""" 40 | if not os.path.exists(nomedir): 41 | print("Il nome che mi hai passato non esiste") 42 | sys.exit(1) 43 | if not os.path.isdir(nomedir): 44 | print("Il nome che mi hai passato esiste, ma non è una directory") 45 | sys.exit(1) 46 | nomeabs = os.path.abspath(nomedir) 47 | dim, nomeg = cerca_grande(nomeabs,set()) 48 | print("-----------------------"); 49 | print(f"Il file più grande è\n {nomeg}\ne ha {dim} bytes") 50 | return 51 | 52 | 53 | # funzione ricorsiva per cercare il file più grande 54 | # nella directory corrente e in tutte le sue sottodirectory 55 | def cerca_grande(nome,dir_esplorate): 56 | """restituisce la coppia (dim,nome) che identifica il file 57 | più grande tra quelli nella directory nome e sottodirectory """ 58 | 59 | assert os.path.isdir(nome), "Argomento deve essere una directory" 60 | print(f"Begin: {nome}",file=sys.stderr) 61 | # inizializzo i due parametri di output 62 | dim_max = -1 63 | nome_max = None 64 | # ottiene il contenuto della directory 65 | listafile = os.listdir(nome) 66 | for f in listafile: 67 | nomecompleto = os.path.join(nome,f) 68 | # verifica se il file è accessibile 69 | if not os.access(nomecompleto,os.F_OK): 70 | print("!! Broken link:", nomecompleto, file=sys.stderr) 71 | continue 72 | # distinguo tra file normali e directory 73 | if not os.path.isdir(nomecompleto): 74 | nuovadim = os.path.getsize(nomecompleto) 75 | nuovonome = nomecompleto 76 | else: 77 | # nomecompleto è una directory: possibile chiamata ricorsiva 78 | # verifico che la directory sia esplorabile 79 | if not os.access(nomecompleto, os.R_OK | os.X_OK): 80 | print(f"!! Directory {nomecompleto} non accessibile",file=sys.stderr) 81 | continue 82 | # verifica che la directory non sia già stata esplorata 83 | # va fatta con il realpath perchè la stessa dir può avere più nomi 84 | nomereal = os.path.realpath(nomecompleto) 85 | if nomereal in dir_esplorate: 86 | print(f"!! Directory {nomereal} già esplorata",file=sys.stderr) 87 | continue 88 | dir_esplorate.add(nomereal) 89 | # directory nuova e accessibile: esegui ricorsione 90 | nuovadim, nuovonome = cerca_grande(nomecompleto,dir_esplorate) 91 | # aggiorno dim se ho trovato file più grande 92 | if nuovadim > dim_max: 93 | dim_max = nuovadim 94 | nome_max = nuovonome 95 | # fine ciclo for su i file di questa directory 96 | print(f"End: {nome}",file=sys.stderr) 97 | return (dim_max, nome_max) 98 | 99 | 100 | # verifico argomenti sulla linea di comando 101 | # e faccio partire la ricerca 102 | if len(sys.argv) == 2: 103 | main(sys.argv[1]) 104 | else: 105 | print("Uso:", sys.argv[0], "nome_directory") 106 | 107 | 108 | -------------------------------------------------------------------------------- /05python/recenti.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Esempio di script per la navigazione del filesystem 4 | e di gestione dei tempi di modifica dei file 5 | 6 | 7 | Comandi per la gestione dei tempi 8 | 9 | time.localtime() # converte secondi da epoch in un oggetto struct_time 10 | time.asctime() # converte un oggetto struct_time in ascii 11 | time.mktime() # inverso di time.localtime() struct_time -> secondi da epoch 12 | 13 | 14 | Comandi per la gestione di file e directory 15 | 16 | os.getcwd() # restituisce directory corrente 17 | os.chdir(path) # cambia directory 18 | os.listdir(path) # elenca file (restituisce lista di stringhe) 19 | os.access(path) # verifica i permessi 20 | os.path.getsize(path) # dimensione file 21 | os.path.exists(path) # vero se il file/directory esiste 22 | os.path.isfile(path) # vero se regular file 23 | os.path.isdir(path) # vero se directory 24 | os.path.islink(path) # vero se symbolic link 25 | os.path.join(nome_dir,nome_file) # combina nome dir e file 26 | os.path.abspath(path) # restituisce path assoluto 27 | os.path.realpath(path) # restituisce nome canonico eliminando link simbolici 28 | os.path.getmtime(path) # istante ultima modifica in secs da epoch 29 | 30 | Lista completa dei comandi su: 31 | https://docs.python.org/3/library/time.html 32 | https://docs.python.org/3/library/os.html 33 | https://docs.python.org/3/library/os.path.html 34 | """ 35 | import os, os.path, sys, time 36 | 37 | def main(nomedir,g): 38 | """Lancia ricerca ricorsiva su nomedir""" 39 | if not os.path.exists(nomedir): 40 | print("Il nome che mi hai passato non esiste") 41 | sys.exit(1) 42 | if not os.path.isdir(nomedir): 43 | print("Il nome che mi hai passato esiste, ma non è una directory") 44 | sys.exit(1) 45 | nomeabs = os.path.abspath(nomedir) 46 | limite = time.mktime(time.localtime()) - g*24*3600 47 | elenco = cerca_recenti(nomeabs,limite,set()) 48 | print("------------------------") 49 | print(f"Ci sono {len(elenco)} file più recenti di {g} giorni"); 50 | for f in elenco: 51 | data = time.asctime(time.localtime(os.path.getmtime(f))) 52 | print(f"{data} {f}") 53 | 54 | 55 | # funzione ricorsiva per cercare i file modificati dopo limite 56 | def cerca_recenti(nome,datalimite,giaesplorati): 57 | """restituisce la lista dei file modificati dopo datalimite 58 | tra quelli nella directory nome e sue sottodirectory""" 59 | 60 | assert os.path.isdir(nome), "Argomento deve essere una directory" 61 | print(f"Begin: {nome}",file=sys.stderr) 62 | # inizializzo la lista di output inizialmente vuota 63 | recenti = [] 64 | # ottiene il contenuto della directory 65 | listafile = os.listdir(nome) 66 | for f in listafile: 67 | nomecompleto = os.path.join(nome,f) 68 | # verifica se il file è accessibile 69 | if not os.access(nomecompleto,os.F_OK): 70 | print("!! Broken link:", nomecompleto, file=sys.stderr) 71 | continue 72 | # distinguo tra file normali e directory 73 | if not os.path.isdir(nomecompleto): 74 | temposec = os.path.getmtime(nomecompleto) 75 | if temposec >= datalimite: 76 | recenti.append(nomecompleto) 77 | else: 78 | # nomecompleto è una directory possibile chiamata ricorsiva 79 | if not os.access(nomecompleto, os.R_OK | os.X_OK): 80 | print(f"!! Directory {nomecompleto} non accessibile",file=sys.stderr) 81 | continue 82 | nomereal = os.path.realpath(nomecompleto) 83 | if nomereal in giaesplorati: 84 | print(f"!! Directory {nomereal} già esplorata",file=sys.stderr) 85 | continue 86 | giaesplorati.add(nomereal) 87 | # directory nuova e accessibile: esegui ricorsione 88 | recenti_subdir = cerca_recenti(nomecompleto,datalimite, giaesplorati) 89 | # concateno al risultato 90 | recenti += recenti_subdir 91 | # ciclo for su i file di questa directory terminato 92 | print(f"End: {nome}",file=sys.stderr) 93 | return recenti 94 | 95 | # invoca main passando il nome di una directory e un numero di giorni 96 | # (anche frazionario) 97 | if len(sys.argv) == 3: 98 | main(sys.argv[1], float(sys.argv[2])) 99 | else: 100 | print("Uso:", sys.argv[0], "nome_directory numero_giorni") 101 | -------------------------------------------------------------------------------- /05python/risultati.txt: -------------------------------------------------------------------------------- 1 | 2 1 Cagliari Atalanta 2 | 2 1 Fiorentina Catania 3 | 2 0 Inter Genoa 4 | 2 1 Lazio Udinese 5 | 0 2 Livorno Roma 6 | 3 0 Napoli Bologna 7 | 0 0 Parma Chievo 8 | 0 1 Sampdoria Juventus 9 | 2 0 Torino Sassuolo 10 | 2 1 Verona Milan 11 | 12 | 2 0 Atalanta Torino 13 | 2 2 Bologna Sampdoria 14 | 0 3 Catania Inter 15 | 2 4 Chievo Napoli 16 | 2 5 Genoa Fiorentina 17 | 4 1 Juventus Lazio 18 | 3 1 Milan Cagliari 19 | 3 0 Roma Verona 20 | 1 4 Sassuolo Livorno 21 | 3 1 Udinese Parma 22 | 23 | 1 1 Fiorentina Cagliari 24 | 1 1 Inter Juventus 25 | 3 0 Lazio Chievo 26 | 2 0 Livorno Catania 27 | 2 0 Napoli Atalanta 28 | 1 3 Parma Roma 29 | 0 3 Sampdoria Genoa 30 | 2 2 Torino Milan 31 | 1 1 Udinese Bologna 32 | 2 0 Verona Sassuolo 33 | 34 | 0 2 Atalanta Fiorentina 35 | 1 2 Bologna Torino 36 | 2 2 Cagliari Sampdoria 37 | 0 0 Catania Parma 38 | 2 1 Chievo Udinese 39 | 0 0 Genoa Livorno 40 | 2 1 Juventus Verona 41 | 1 2 Milan Napoli 42 | 2 0 Roma Lazio 43 | 0 7 Sassuolo Inter 44 | 45 | 3 3 Bologna Milan 46 | 1 2 Chievo Juventus 47 | 2 1 Inter Fiorentina 48 | 3 1 Lazio Catania 49 | 1 1 Livorno Cagliari 50 | 1 1 Napoli Sassuolo 51 | 4 3 Parma Atalanta 52 | 0 2 Sampdoria Roma 53 | 2 2 Torino Verona 54 | 1 0 Udinese Genoa 55 | 56 | 2 0 Atalanta Udinese 57 | 1 1 Cagliari Inter 58 | 2 0 Catania Chievo 59 | 2 2 Fiorentina Parma 60 | 0 2 Genoa Napoli 61 | 1 0 Milan Sampdoria 62 | 5 0 Roma Bologna 63 | 2 2 Sassuolo Lazio 64 | 0 1 Torino Juventus 65 | 2 1 Verona Livorno 66 | 67 | 1 4 Bologna Verona 68 | 1 1 Catania Genoa 69 | 0 1 Chievo Atalanta 70 | 0 3 Inter Roma 71 | 3 2 Juventus Milan 72 | 0 0 Lazio Fiorentina 73 | 4 0 Napoli Livorno 74 | 3 1 Parma Sassuolo 75 | 2 2 Sampdoria Torino 76 | 2 0 Udinese Cagliari 77 | 78 | 2 1 Atalanta Lazio 79 | 2 1 Cagliari Catania 80 | 4 2 Fiorentina Juventus 81 | 2 1 Genoa Chievo 82 | 1 2 Livorno Sampdoria 83 | 1 0 Milan Udinese 84 | 2 0 Roma Napoli 85 | 2 1 Sassuolo Bologna 86 | 3 3 Torino Inter 87 | 3 2 Verona Parma 88 | 89 | 1 0 Bologna Livorno 90 | 0 0 Catania Sassuolo 91 | 1 2 Chievo Fiorentina 92 | 4 2 Inter Verona 93 | 2 0 Juventus Genoa 94 | 2 0 Lazio Cagliari 95 | 2 0 Napoli Torino 96 | 3 2 Parma Milan 97 | 1 0 Sampdoria Atalanta 98 | 0 1 Udinese Roma 99 | 100 | 1 1 Atalanta Inter 101 | 0 3 Cagliari Bologna 102 | 1 2 Fiorentina Napoli 103 | 1 0 Genoa Parma 104 | 4 0 Juventus Catania 105 | 3 3 Livorno Torino 106 | 1 1 Milan Lazio 107 | 1 0 Roma Chievo 108 | 1 2 Sassuolo Udinese 109 | 2 0 Verona Sampdoria 110 | 111 | 0 0 Bologna Chievo 112 | 0 2 Lazio Genoa 113 | 1 0 Livorno Atalanta 114 | 0 2 Milan Fiorentina 115 | 2 1 Napoli Catania 116 | 0 1 Parma Juventus 117 | 3 4 Sampdoria Sassuolo 118 | 1 1 Torino Roma 119 | 0 3 Udinese Inter 120 | 2 1 Verona Cagliari 121 | -------------------------------------------------------------------------------- /05python/serieA.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | """ 3 | Esercizio che costruisce una classifica dati i 4 | risultati di un insieme di partite scritte in un file 5 | 6 | 7 | Uso un dizionario per rappresentare la classifica con 8 | chiave: nome squadra 9 | valore: array di 3 elementi: [punteggio, gol fatti, gol subiti] 10 | Per convenzione se una squadra non è nel dizionario 11 | assumiamo abbia punteggio 0 e 0 gol fatti o subiti 12 | 13 | La classifica finale viene costruita ordinando 14 | le squadre per punteggio e differenza reti 15 | Le squadre che hanno gli stessi punti e differenza 16 | reti sono ordinate lessicograficamente 17 | (ad esempio Livorno e Parma) 18 | 19 | sorting howto: 20 | https://docs.python.org/3/howto/sorting.html 21 | 22 | with statement 23 | https://realpython.com/python-with-statement/ 24 | """ 25 | 26 | 27 | # import necessario per leggere gli argomenti 28 | # sulla linea di comando in sys.argv 29 | import sys 30 | 31 | 32 | def aggiorna_classifica(c,s1,g1,s2,g2): 33 | """Aggiorna per s1 e s2 i punti i gol fatti e subiti. 34 | Per ogni squadra nella classifica associo al nome 35 | l'array di 3 elementi: [punti, gf, gs]""" 36 | # calcolo i punti assegnati alle squadre 37 | if g1>g2: 38 | p1=3 39 | p2=0 40 | elif g12 vuol dire usare 2 spazi e giustificare a destra 86 | print(f"{nome:<12} {punti:>2} {golf:>2} {gols:>2}") 87 | 88 | 89 | def main(nomefile): 90 | with open(nomefile,"r") as f: 91 | # viene restituito il dizionario c contenente la classifica 92 | c = crea_classifica(f) 93 | # all'uscita del with il file f viene automaticamente chiuso 94 | squadre = list(c) # crea un array con le chiavi 95 | squadre.sort() # ordina lessicograficamente 96 | # ordina per valori decrescenti di punti e differenza reti 97 | # per ogni squadra x c[x] è l'array con punti,golfatti,golsubiti 98 | # quindi c[x][0] sono i punti, c[x][1]-c[x][2] la differenza reti 99 | # Usiamo il fatto che gli array di 2 elementi sono confrontati 100 | # componente per componente 101 | squadre.sort(key=lambda x: [c[x][0], c[x][1]-c[x][2]], reverse=True) 102 | # stampa intestazione classifica 103 | print("-----------------------") 104 | print("Squadra Pu GF GS") 105 | print("-----------------------") 106 | # stampo la classifica secondo l'ordinamento ottenuto 107 | for s in squadre: 108 | stampa_squadra(s,c[s][0],c[s][1],c[s][2]) 109 | return 110 | 111 | 112 | if len(sys.argv)==2: 113 | main(sys.argv[1]) 114 | else: 115 | print(f"Uso:\n\t{sys.argv[0]} nomefile") 116 | 117 | -------------------------------------------------------------------------------- /05python/vip.py: -------------------------------------------------------------------------------- 1 | """ 2 | Esempio definizione di una classe in python con particolare riferimento ai metodi 3 | __eq__ e __hash__ per la gestione di liste, set(), e dizionari 4 | 5 | Per approfondire: 6 | https://docs.python.org/3/reference/datamodel.html#special-method-names 7 | """ 8 | 9 | import time 10 | 11 | class Vip: 12 | 13 | def __init__(self,n,c,citta="Roma"): 14 | """Costruisci il vip dato nome e cognome 15 | se non viene fornita la residenza viene assegnata a Roma""" 16 | self.nome = n 17 | self.cognome = c 18 | self.residenza = citta 19 | 20 | 21 | def riposa(self,t): 22 | """riposa per un numero assegnato di secondi""" 23 | print(self.nome, "...") 24 | time.sleep(t) 25 | print("...", self.cognome) 26 | 27 | def __str__(self): 28 | """metodo invocato da print/str/etc""" 29 | return self.nome + " " +self.cognome +f" ({self.residenza})" 30 | 31 | def __eq__(self,v): 32 | """ metodo invocato da ==""" 33 | return self.nome == v.nome and self.cognome == v.cognome and self.residenza == v.residenza 34 | 35 | def __hash__(self): 36 | """metodo necessario per usare i Vip in set 37 | e come chiavi di dict""" 38 | h = hash((self.nome,self.cognome,self.residenza)) 39 | # per debug mostriamo l'oggetto e il corrispondente hash 40 | print(f"Hash({self}) --> {h}") 41 | return h 42 | 43 | 44 | # esempi di operazioni con elementi della classe 45 | totti = Vip("Francesco","Totti") 46 | renga = Vip("Francesco","Renga") 47 | chiara = Vip("Chiara","Ferragni","Milano") 48 | capitano = Vip("Francesco","Totti") 49 | # crea lista 50 | isola = [totti, Vip("Ilary","Blasi")] 51 | 52 | # crea set 53 | stadio = {Vip("Francesco","Totti"), Vip("Ilary","Blasi")} 54 | 55 | 56 | # crea dizionario 57 | followers = {Vip("Chiara","Ferragni","Milano"):3000} 58 | # cambiando la residenza la chiave chiara non viene più trocata 59 | print(chiara in followers) 60 | chiara.residenza = "Monza" 61 | print(chiara in followers) 62 | # la morale è che per non avere problemi 63 | # gli oggetti memorizzati in set() o usati 64 | # come chiavi nei dizionari devono essere immutabili 65 | # Ad esempio: stringhe e interi o tuple (contenti oggetti immutabili) 66 | 67 | -------------------------------------------------------------------------------- /06processi/Mini introduzione alle System Calls.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Laboratorio2B/2324-Lab2B/8000dd55ee0b9a79c6ad8dd690457f398e53e19a/06processi/Mini introduzione alle System Calls.pdf -------------------------------------------------------------------------------- /06processi/contaprimi.c: -------------------------------------------------------------------------------- 1 | #include "xerrori.h" 2 | 3 | // programma per il conteggio di numero dei primi in un 4 | // intervallo usando piu' processi ausiliari 5 | // e una pipe per comunicare i conteggi parziali 6 | // al processo genitore 7 | 8 | 9 | // restituisce true/false a seconda che n sia primo o composto 10 | bool primo(int n) 11 | { 12 | if(n<2) return false; 13 | if(n%2==0) { 14 | if(n==2) return true; 15 | else return false; } 16 | for (int i=3; i*i<=n; i += 2) 17 | if(n%i==0) return false; 18 | return true; 19 | } 20 | 21 | // conta i primi in [a,b) 22 | int contap(int a, int b) 23 | { 24 | int tot = 0; 25 | for(int i=a;i0 && n1>=n0 && p>0); 41 | // creo una pipe di comunicazione dai figli al genitore 42 | int up[2]; // la chiamo up perchè la uso da figli a genitore 43 | xpipe(up,__LINE__,__FILE__); 44 | // generazione dei processi child 45 | for(int i=0;i0); 31 | // creo una pipe di comunicazione dai figli al genitore 32 | int up[2]; // la chiamo up perchè la uso da figli a genitore 33 | xpipe(up,__LINE__,__FILE__); 34 | int down[2]; 35 | xpipe(down,__LINE__,__FILE__); 36 | for(int i=0;i // permette di usare scanf printf etc ... 3 | #include // conversioni stringa exit() etc ... 4 | #include // gestisce tipo bool 5 | #include // permette di usare la funzione ass 6 | #include // funzioni per stringhe 7 | #include // richiesto per usare errno 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | // primo esempio di generazione di un processo figlio mediante fork 15 | 16 | // mostra anche la differenza di prestazioni fra fwrite e write 17 | // quando vengono effettuate numerose operazioni di scrittura 18 | // di piccole quantità di byte (nel nostro esempio n interi vengono 19 | // scritti uno alla volta) 20 | 21 | 22 | int main(int argc, char *argv[]) 23 | { 24 | if(argc!=2) { 25 | printf("Uso: %s intero_positivo\n",argv[0]); 26 | exit(1); 27 | } 28 | int n = atoi(argv[1]); 29 | // fork crea un nuovo processo 30 | pid_t p = fork(); 31 | if(p==0) { 32 | // codice eseguito dal processo figlio 33 | printf("Io sono %d figlio di %d\n",getpid(),getppid()); 34 | FILE *f = fopen("file_figlio.txt","w"); 35 | for(int i=0;i0) { 40 | // codice del processo padre 41 | printf("Io sono %d genitore di %d\n",getpid(),p); 42 | // mode 0607 indica i rw----rwx ma i permessi reali dipenderanno anche da umask 43 | int fd = open("file_padre.txt",O_WRONLY|O_CREAT|O_TRUNC,0607); 44 | for(int i=0;i0, "L'input deve essere positivo" 13 | if n==1: 14 | return False 15 | if n==2: 16 | return True 17 | if n%2 == 0: 18 | return False 19 | assert n>=3 and n%2==1, "C'e' qualcosa che non funziona" 20 | for i in range(3,n//2,2): 21 | if n%i==0: 22 | return False 23 | if i*i > n: 24 | break 25 | return True 26 | 27 | 28 | def main(n,cifre): 29 | tot_primi = 0 30 | for i in range(n): 31 | x = random.randint(0, 10**(cifre)) 32 | if x%2==0: 33 | x += 1 34 | while x%3==0 or x%5 ==0 or x%7==0: 35 | x += 2 36 | if primo(x): 37 | tot_primi += 1 38 | print(x) 39 | print("Trovati",tot_primi,"primi",file=sys.stderr) 40 | 41 | if len(sys.argv)!=3: 42 | print("Uso:\n\t %s numero_interi cifre" % sys.argv[0]) 43 | else: 44 | main(int(sys.argv[1]), int(sys.argv[2]) ) 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /06processi/xerrori.h: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE // permette di usare estensioni GNU 2 | #include // permette di usare scanf printf etc ... 3 | #include // conversioni stringa exit() etc ... 4 | #include // gestisce tipo bool 5 | #include // permette di usare la funzione ass 6 | #include // funzioni per stringhe 7 | #include // richiesto per usare errno 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include /* For mode constants */ 16 | #include /* For O_* constants */ 17 | 18 | 19 | // termina programma 20 | void termina(const char *s); 21 | void xtermina(const char *s, int linea, char *file); 22 | 23 | // operazioni su FILE * 24 | FILE *xfopen(const char *path, const char *mode, int linea, char *file); 25 | 26 | // operazioni su file descriptors 27 | void xclose(int fd, int linea, char *file); 28 | 29 | // operazioni su processi 30 | pid_t xfork(int linea, char *file); 31 | pid_t xwait(int *status, int linea, char *file); 32 | // pipes 33 | int xpipe(int pipefd[2], int linea, char *file); 34 | 35 | 36 | // memoria condivisa POSIX 37 | int xshm_open(const char *name, int oflag, mode_t mode, int linea, char *file); 38 | int xshm_unlink(const char *name, int linea, char *file); 39 | int xftruncate(int fd, off_t length, int linea, char *file); 40 | void *simple_mmap(size_t length, int fd, int linea, char *file); 41 | int xmunmap(void *addr, size_t length, int linea, char *file); 42 | 43 | // semafori POSIX 44 | sem_t *xsem_open(const char *name, int oflag, mode_t mode, unsigned int value, int linea, char *file); 45 | int xsem_unlink(const char *name, int linea, char *file); 46 | int xsem_close(sem_t *sem, int linea, char *file); 47 | int xsem_init(sem_t *sem, int pshared, unsigned int value, int linea, char *file); 48 | int xsem_post(sem_t *sem, int linea, char *file); 49 | int xsem_wait(sem_t *sem, int linea, char *file); 50 | -------------------------------------------------------------------------------- /07shmsem/contaprimi_sem.c: -------------------------------------------------------------------------------- 1 | #include "xerrori.h" 2 | 3 | // conteggio dei primi con piu' processi utilizzando 4 | // una singola variabile condivisa il cui accesso è 5 | // regolato dal semaforo Nome 6 | 7 | // un secondo semaforo Nome2 è utilizzato per permettere 8 | // al processo padre di stabilire quando tutti i processi 9 | // ausiliari hanno terminato il calcolo dei primi 10 | 11 | // NOTA: questo programma ha solo interesse didattico: 12 | // dal punto di vista delle prestazionei è una pessima idea 13 | // utilizzare una sola variabile condivisa a cui i processi 14 | // accedono continuamente. 15 | 16 | // Inoltre in questo caso i processi figli non fanno altre 17 | // operazioni dopo il calcolo dei primi quindi il meccanismo 18 | // della wait nel processo padre si potrebbe utilizzare 19 | 20 | // La soluzione in contaprimi_shm.c è quindi preferibile 21 | 22 | 23 | 24 | // nomi della shared memory e dei semafori 25 | // ai nomi dei semafori viene automaticamente 26 | // aggiunto il prefisso .sem 27 | #define Nome "/contaprimi" 28 | #define Nome2 "/contaprimi2" 29 | 30 | 31 | //Prototipi 32 | bool primo(int n); 33 | 34 | int main(int argc,char *argv[]) 35 | { 36 | if(argc!=3) { 37 | fprintf(stderr,"Uso\n\t%s m num_processi\n", argv[0]); 38 | exit(1); 39 | } 40 | // conversione input 41 | int m= atoi(argv[1]); 42 | if(m<1) termina("limite primi non valido"); 43 | int p= atoi(argv[2]); 44 | if(p<=0) termina("numero di processi non valido"); 45 | 46 | // ---- creazione array memoria condivisa 47 | int shm_size = sizeof(int); // uso solo 4 byte di memoria condivisa (a[0]) 48 | int fd = xshm_open(Nome,O_RDWR | O_CREAT, 0660,__LINE__,__FILE__); 49 | xftruncate(fd, shm_size, __LINE__,__FILE__); 50 | int *a = simple_mmap(shm_size,fd, __LINE__,__FILE__); 51 | close(fd); // dopo mmap e' possibile chiudere il file descriptor 52 | xshm_unlink(Nome,__LINE__, __FILE__); // distrugge shm quando finito 53 | 54 | // ---- creo il semaforo 55 | sem_t *sem_a0 = xsem_open(Nome,O_CREAT|O_EXCL,0666,1, 56 | __LINE__, __FILE__); 57 | xsem_unlink(Nome,__LINE__, __FILE__); // distrugge sem quando finito 58 | // ---- creo il secondo semaforo 59 | sem_t *sem_finito = xsem_open(Nome2,O_CREAT|O_EXCL,0666,0, 60 | __LINE__, __FILE__); 61 | xsem_unlink(Nome2,__LINE__, __FILE__); // distrugge sem quando finito 62 | 63 | // creazione processi figlio 64 | *a = 0; 65 | for(int i=0; i 3 | 4 | // algoritmo di sorting con 2 processi e memoria condivisa 5 | // l'array di input viene messo in una memoria condivisa 6 | // viene chiamato partition e poi la prima metà è ordinata 7 | // da sort3.out mentre questo processo ordina la seconda metà 8 | // solo dimostrativo: non è un metodo efficiente!!! 9 | 10 | // funzione di partizionamento tipo quicksort 11 | int partition(int a[], int n); 12 | 13 | 14 | // funzione di comparazione per qsort 15 | int cmp(const void *a, const void *b) 16 | { 17 | return *(int*)a - *(int*)b; 18 | } 19 | 20 | 21 | int main(int argc,char *argv[]) 22 | { 23 | if(argc!=3) { 24 | fprintf(stderr,"Uso\n\t%s dim_array nome_shm\n", argv[0]); 25 | exit(1); 26 | } 27 | // conversione input 28 | int n= atoi(argv[1]); 29 | if(n<=1) termina("dimensione non valida"); 30 | 31 | // ---- creazione array memoria condivisa 32 | int shm_size = n*sizeof(int); // un intero x processo 33 | int fd = xshm_open(argv[2],O_RDWR | O_CREAT, 0660,__LINE__,__FILE__); 34 | xftruncate(fd, shm_size, __LINE__,__FILE__); 35 | int *a = simple_mmap(shm_size,fd, __LINE__,__FILE__); 36 | close(fd); // dopo mmap e' possibile chiudere il file descriptor 37 | // non effettuo la cancellazione per poter esaminare l'array dalla linea di comando 38 | 39 | // ---- inizializza array condiviso con interi random 40 | srand(1); // inizializza numeri casuali con lo stesso seed 41 | for(int i=0; i1); 101 | // scelgo pivot in posizione random 102 | int k = random() % n; // genero posizione random del pivot 103 | int pivot = a[k]; // elemento pivot 104 | a[k]=a[0];a[0]=pivot; // scambia a[k]<->a[0] per mettere il pivot in a[0] 105 | 106 | // procedura di partizionamento 107 | // l'elemento pivot svolge anche la funzione di sentinella 108 | int i= -1; // puntatore oltre estremo sinistro 109 | int j = n; //puntatore oltre estremo destro 110 | while(1) { 111 | while(a[--j]>pivot) 112 | ; // esce se a[j]<=pivot 113 | while(a[++i]=pivot 115 | if(i a[j] 117 | int t=a[i]; a[i]=a[j]; a[j]=t; 118 | } 119 | else break; 120 | } 121 | // la prima meta' e' a[0] .. a[j] quindi ha j+1 elementi 122 | assert(j+1 >0); 123 | assert(j+1 < n); 124 | printf("Pivot: %d, dimensione prima partizione: %d\n",pivot,j+1); 125 | return j+1; 126 | } 127 | -------------------------------------------------------------------------------- /07shmsem/sommaprimi.c: -------------------------------------------------------------------------------- 1 | #include "xerrori.h" 2 | 3 | // calcola il numero e la somma dei primi contenuti 4 | // alcuni file di testo 5 | // utilizza dei processi ausiliari per il conteggio 6 | // la comunicazione avviene attraverso 7 | // shared memory e con il controllo di alcuni semafori 8 | 9 | // il programma ha solo interesse didattico: 10 | // la soluzione implementata è molto inefficiente 11 | 12 | 13 | #define Sommamem "/sommaprimi" 14 | #define SommasemX "/sommaprimiX" 15 | #define SommasemI "/sommaprimiI" 16 | #define SommasemF "/sommaprimiF" 17 | 18 | 19 | 20 | int main(int argc, char *argv[]) 21 | { 22 | if(argc<2) { 23 | printf("Uso:\n\t%s file1 [file2 file3 ...] \n",argv[0]); 24 | exit(1); 25 | } 26 | 27 | // ---- creazione array memoria condivisa 28 | int shm_size = sizeof(int)+sizeof(long); // uso solo 4+8=12 byte di memoria condivisa (a[0]) 29 | int fd = xshm_open(Sommamem,O_RDWR | O_CREAT, 0660,__LINE__,__FILE__); 30 | xftruncate(fd, shm_size, __LINE__,__FILE__); 31 | int *nump = simple_mmap(shm_size,fd, __LINE__,__FILE__); 32 | long *sommap = (long *) (nump + 1); 33 | close(fd); // dopo mmap e' possibile chiudere il file descriptor 34 | 35 | // ---- creo i semafori 36 | sem_t *semX = xsem_open(SommasemX,O_CREAT|O_EXCL,0666,1,__LINE__, __FILE__); 37 | sem_t *semI = xsem_open(SommasemI,O_CREAT|O_EXCL,0666,0,__LINE__, __FILE__); 38 | sem_t *semF = xsem_open(SommasemF,O_CREAT|O_EXCL,0666,0,__LINE__, __FILE__); 39 | // inizializzo variabili condivise 40 | *nump = 0; 41 | *sommap = 0; 42 | 43 | // faccio partire i processi ausiliari 44 | int aux = argc-1; // numero processi ausiliari 45 | for(int i=0;i 3 | 4 | // programma che esegue il sorting di un oggetto 5 | // di memoria condivisa passato dalla linea 6 | // di comando 7 | 8 | // prende come input il nome di un oggetto di 9 | // memoria condivisa, e il numero di interi 10 | // da ordinare 11 | 12 | // produce un errore se invocato direttamente 13 | // dalla linea di comando 14 | 15 | 16 | // funzione di comparazione per qsort 17 | int cmp(const void *a, const void *b) 18 | { 19 | return *(int*)a - *(int*)b; 20 | } 21 | 22 | 23 | int main(int argc,char *argv[]) 24 | { 25 | if(argc!=3) { 26 | fprintf(stderr,"Uso\n\t%s nome_shm num_interi\n", argv[0]); 27 | exit(1); 28 | } 29 | printf("Sto eseguendo: %s %s %s\n",argv[0],argv[1],argv[2]); 30 | 31 | // conversione numero di interi 32 | int n= atoi(argv[2]); 33 | if(n<1) termina("dimensione non valida"); 34 | 35 | // ---- apertura oggetto memoria condivisa 36 | int shm_size = n*sizeof(int); // un intero x processo 37 | int fd = xshm_open(argv[1],O_RDWR, 0660,__LINE__,__FILE__); 38 | int *a = simple_mmap(shm_size,fd, __LINE__,__FILE__); 39 | close(fd); // dopo mmap e' possibile chiudere il file descriptor 40 | 41 | // ordina gli interi nella memoria condivisa 42 | qsort(a, n, sizeof(int), cmp); 43 | 44 | // unmap memoria condivisa e termina 45 | xmunmap(a,shm_size,__LINE__, __FILE__); 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /07shmsem/xerrori.h: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE // permette di usare estensioni GNU 2 | #include // permette di usare scanf printf etc ... 3 | #include // conversioni stringa exit() etc ... 4 | #include // gestisce tipo bool 5 | #include // permette di usare la funzione ass 6 | #include // funzioni per stringhe 7 | #include // richiesto per usare errno 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include /* For mode constants */ 16 | #include /* For O_* constants */ 17 | 18 | 19 | // termina programma 20 | void termina(const char *s); 21 | void xtermina(const char *s, int linea, char *file); 22 | 23 | // operazioni su FILE * 24 | FILE *xfopen(const char *path, const char *mode, int linea, char *file); 25 | 26 | // operazioni su file descriptors 27 | void xclose(int fd, int linea, char *file); 28 | 29 | // operazioni su processi 30 | pid_t xfork(int linea, char *file); 31 | pid_t xwait(int *status, int linea, char *file); 32 | // pipes 33 | int xpipe(int pipefd[2], int linea, char *file); 34 | 35 | 36 | // memoria condivisa POSIX 37 | int xshm_open(const char *name, int oflag, mode_t mode, int linea, char *file); 38 | int xshm_unlink(const char *name, int linea, char *file); 39 | int xftruncate(int fd, off_t length, int linea, char *file); 40 | void *simple_mmap(size_t length, int fd, int linea, char *file); 41 | int xmunmap(void *addr, size_t length, int linea, char *file); 42 | 43 | // semafori POSIX 44 | sem_t *xsem_open(const char *name, int oflag, mode_t mode, unsigned int value, int linea, char *file); 45 | int xsem_unlink(const char *name, int linea, char *file); 46 | int xsem_close(sem_t *sem, int linea, char *file); 47 | int xsem_init(sem_t *sem, int pshared, unsigned int value, int linea, char *file); 48 | int xsem_post(sem_t *sem, int linea, char *file); 49 | int xsem_wait(sem_t *sem, int linea, char *file); 50 | -------------------------------------------------------------------------------- /08threads/ProdCons.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Laboratorio2B/2324-Lab2B/8000dd55ee0b9a79c6ad8dd690457f398e53e19a/08threads/ProdCons.pdf -------------------------------------------------------------------------------- /08threads/TempiProdConsC.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Laboratorio2B/2324-Lab2B/8000dd55ee0b9a79c6ad8dd690457f398e53e19a/08threads/TempiProdConsC.ods -------------------------------------------------------------------------------- /08threads/contaprimi.c: -------------------------------------------------------------------------------- 1 | #include "xerrori.h" 2 | 3 | // primo esempio di utilizzo di thread 4 | // conteggio dei primi con thread multipli 5 | 6 | // mostra come usare una struct per condividere dei parametrei 7 | // di input e output tra thread principale e ausiliari 8 | 9 | 10 | //Prototipi 11 | bool primo(int n); 12 | 13 | // struct che uso per passare argomenti ai thread 14 | typedef struct { 15 | int start; // intervallo dove cercare i primo 16 | int end; // parametri di input 17 | int somma_parziale; // parametro di output 18 | } dati; 19 | 20 | // funzione passata a pthred_create 21 | void *tbody(void *v) { 22 | dati *d = (dati *) v; 23 | int primi = 0; 24 | // cerco i primi nell'intervallo assegnato 25 | for(int j=d->start;jend;j++) { 26 | if(primo(j)) primi++; 27 | } 28 | fprintf(stderr, "Il thread che partiva da %d ha terminato\n", d->start); 29 | d->somma_parziale = primi; 30 | pthread_exit(NULL); 31 | } 32 | 33 | int main(int argc,char *argv[]) 34 | { 35 | if(argc!=3) { 36 | fprintf(stderr,"Uso\n\t%s m num_threads\n", argv[0]); 37 | exit(1); 38 | } 39 | // conversione input 40 | int m= atoi(argv[1]); 41 | if(m<1) termina("limite primi non valido"); 42 | int p= atoi(argv[2]); 43 | if(p<=0) termina("numero di thread non valido"); 44 | 45 | // creazione thread ausiliari 46 | pthread_t t[p]; // array di p indentificatori di thread 47 | dati d[p]; // array di p struct che passerò ai p thread 48 | int somma = 0; // variabile dove accumulo il numero di primi 49 | for(int i=0; i0); 22 | int d = 0; 23 | for (int i=1; i<=n; i ++) 24 | if(n%i==0) d++; 25 | return d; 26 | } 27 | 28 | // struct contenente i parametri di input 29 | // per i thread consumatori 30 | typedef struct { 31 | int *buffer; 32 | int *pcindex; 33 | pthread_mutex_t *pmutex_buf; 34 | pthread_mutex_t *pmutex_file; 35 | sem_t *sem_free_slots; 36 | sem_t *sem_data_items; 37 | FILE *outfile; 38 | } dati_consumatori; 39 | 40 | // struct contenente i parametri di input 41 | // per i thread produttori 42 | typedef struct { 43 | int *buffer; 44 | int *ppindex; 45 | pthread_mutex_t *pmutex_buf; 46 | sem_t *sem_free_slots; 47 | sem_t *sem_data_items; 48 | char *nomefile; 49 | } dati_produttori; 50 | 51 | 52 | 53 | // funzione eseguita dai thread consumer 54 | void *cbody(void *arg) 55 | { 56 | dati_consumatori *a = (dati_consumatori *)arg; 57 | 58 | puts("consumatore partito"); 59 | int n; 60 | do { 61 | xsem_wait(a->sem_data_items,__LINE__,__FILE__); 62 | xpthread_mutex_lock(a->pmutex_buf,QUI); 63 | n = a->buffer[*(a->pcindex) % Buf_size]; 64 | *(a->pcindex) +=1; 65 | xpthread_mutex_unlock(a->pmutex_buf,QUI); 66 | xsem_post(a->sem_free_slots,__LINE__,__FILE__); 67 | if(n == -1) break; 68 | int div = divisori(n); 69 | xpthread_mutex_lock(a->pmutex_file,QUI); 70 | fprintf(a->outfile,"%d %d\n",n,div); 71 | xpthread_mutex_unlock(a->pmutex_file,QUI); 72 | } while(true); 73 | puts("Consumatore sta per finire"); 74 | pthread_exit(NULL); 75 | } 76 | 77 | // funzione eseguita dai thread producer 78 | void *pbody(void *arg) 79 | { 80 | dati_produttori *a = (dati_produttori *)arg; 81 | 82 | puts("produttore partito"); 83 | // apre il file e termina se non riesce 84 | FILE *f = fopen(a->nomefile,"rt"); 85 | if(f==NULL) { 86 | fprintf(stderr,"Apertura file %s fallita\n",a->nomefile); 87 | pthread_exit(NULL); 88 | } 89 | int n; 90 | do { 91 | int e = fscanf(f,"%d",&n); 92 | if(e!=1) break; 93 | xsem_wait(a->sem_free_slots,QUI); 94 | xpthread_mutex_lock(a->pmutex_buf,QUI); 95 | a->buffer[*(a->ppindex) % Buf_size] = n; 96 | *(a->ppindex) +=1; 97 | xpthread_mutex_unlock(a->pmutex_buf,QUI); 98 | xsem_post(a->sem_data_items,QUI); 99 | } while(true); 100 | puts("produttore sta per finire"); 101 | pthread_exit(NULL); 102 | } 103 | 104 | // main: da completare 105 | int main(int argc, char *argv[]) 106 | { 107 | // leggi input 108 | if(argc<4) { 109 | printf("Uso\n\t%s file1 [file2 ...] outfile numt\n", argv[0]); 110 | exit(1); 111 | } 112 | // numero di thread prod e consumatori 113 | int tp = argc-3; 114 | int tc = atoi(argv[argc-1]); 115 | assert(tp>0); 116 | assert(tc>0); 117 | FILE* outfile = fopen(argv[argc-2],"wt"); 118 | if(outfile==NULL) 119 | xtermina("impossibile aprire outfile",QUI); 120 | 121 | // buffer produttori-consumatori 122 | int buffer[Buf_size]; 123 | int pindex=0, cindex=0; 124 | pthread_mutex_t mupbuf = PTHREAD_MUTEX_INITIALIZER; 125 | pthread_mutex_t mucbuf = PTHREAD_MUTEX_INITIALIZER; 126 | pthread_mutex_t mucfile = PTHREAD_MUTEX_INITIALIZER; 127 | sem_t sem_free_slots, sem_data_items; 128 | xsem_init(&sem_free_slots,0,Buf_size,__LINE__,__FILE__); 129 | xsem_init(&sem_data_items,0,0,__LINE__,__FILE__); 130 | 131 | // dati per i thread 132 | dati_produttori ap[tp]; 133 | dati_consumatori ac[tc]; 134 | pthread_t prod[tp]; // id thread produttori 135 | pthread_t cons[tc]; // id thread consumatori 136 | 137 | 138 | // Da completare: 139 | 140 | // creo tutti i produttori 141 | // creo tutti i consumatori 142 | 143 | // attendo i produttori 144 | 145 | // comunico ai consumatori che possono terminare 146 | // attendo i consumatori 147 | 148 | // deallocazione, saluti, etc.... 149 | 150 | return 0; 151 | } 152 | 153 | -------------------------------------------------------------------------------- /08threads/divisori.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | 3 | # programma divisori.py 4 | # calcola il numeri di divisori degli interi dati nei file di input 5 | 6 | import sys 7 | 8 | def main(infiles): 9 | for infile in infiles: 10 | with open(infile,"r") as f: 11 | for s in f: 12 | x = int(s) 13 | d = divisori(x) 14 | print(x,d) 15 | 16 | def divisori( n ): 17 | assert(n>0) 18 | tot = 0 19 | for i in range ( 1,n+1 ): 20 | if n%i==0: 21 | tot += 1 22 | return tot 23 | 24 | 25 | if len(sys.argv)<2: 26 | print("Uso:\n\t %s infile1 infile2 ... infile3" % sys.argv[0]) 27 | else: 28 | main(sys.argv[1:]) 29 | -------------------------------------------------------------------------------- /08threads/esercizioDivisori.md: -------------------------------------------------------------------------------- 1 | ## Esercizio calcolo numero divisori 2 | 3 | Scrivere un programma *divisoriT* che invocato dalla linea di comando scrivendo 4 | 5 | divisoriT infile1 infile2 infile3 ... infileN outfile numt 6 | 7 | con *numt>0* legge gli interi positivi contenuti nei file *infile1*, ... , *infileN*, e crea un file *outfile* contenente gli stessi interi e di fianco ad ogni intero il numero dei suoi divisori. 8 | 9 | Il thread principale deve per prima cosa creare *N* thread produttori ad ognuno dei quali deve essere assegnato uno dei file di input. Ogni thread produttore deve leggere gli interi dal suo file, utilizzando ad esempio fscanf, e scriverli nel buffer produttori/consumatori condiviso. Ognuno di questi interi viene messo sul buffer produttore/consumatori e rappresenta una unità di lavoro per i consumatori. Il buffer deve avere una dimensione definita con *#define*. 10 | 11 | Il thread principale deve successivamente aprire il file di output e creare *numt* thread consumatori ognuno dei quali deve ripetutamente: 12 | 13 | * leggere dal buffer un intero 14 | 15 | * calcolare il numero dei suoi divisori 16 | 17 | * scrivere nel file di output l'intero seguito dal numero dei suoi divisori (sulla stessa riga) 18 | 19 | Come in tutti gli schemi produttore-consumatore è necessario stabilire un meccanismo che permetta ai produttori di segnalare ai consumatori che non ci sono altri valori da elaborare. 20 | 21 | Si noti che tutti i consumatori scrivono sullo stesso file di output, è quindi necessario regolarne l'accesso mediante un mutex. Il file di output deve essere chiuso dal thread principale quando tutti i thread secondari sono terminati. 22 | 23 | 24 | ## Esperimenti 25 | 26 | Usare il programma *interi.py* per generare dei file di interi, e il programma *divisori.py* per generare il corrispondente file di divisori. Il vostro output può differire da quello prodotto da *divisori.py* per l'ordine delle righe; usare il comando `sort -n` per ottenere dei file con gli interi ordinati dal più piccolo al più grande. 27 | 28 | -------------------------------------------------------------------------------- /08threads/interi.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | 3 | # programma numeri.py 4 | # crea un file di testo contenente un numero assegnato di interi positivi 5 | 6 | import random 7 | import sys 8 | 9 | def main(n,nomefile): 10 | f = open(nomefile,"w"); 11 | assert(f!=None); 12 | for i in range( n ): 13 | x = random.randint(1, 2**20) 14 | print(x,file=f) 15 | f.close(); 16 | 17 | if len(sys.argv)!=3: 18 | print("Uso:\n\t %s numero_interi outfile" % sys.argv[0]) 19 | else: 20 | main(int(sys.argv[1]), sys.argv[2] ) 21 | -------------------------------------------------------------------------------- /08threads/makefile: -------------------------------------------------------------------------------- 1 | # definizione del compilatore e dei flag di compilazione 2 | # che vengono usate dalle regole implicite 3 | CC=gcc 4 | CFLAGS=-std=c11 -Wall -g -O3 -pthread 5 | LDLIBS=-lm -lrt -pthread 6 | 7 | 8 | # su https://www.gnu.org/software/make/manual/make.html#Implicit-Rules 9 | # sono elencate le regole implicite e le variabili 10 | # usate dalle regole implicite 11 | 12 | # Variabili automatiche: https://www.gnu.org/software/make/manual/make.html#Automatic-Variables 13 | # nei comandi associati ad ogni regola: 14 | # $@ viene sostituito con il nome del target 15 | # $< viene sostituito con il primo prerequisito 16 | # $^ viene sostituito con tutti i prerequisiti 17 | 18 | # elenco degli eseguibili da creare 19 | EXECS=contaprimi.out tabella_primi.out prodcons.out divisori.out pctest.out pctestCV.out gcdT.out 20 | 21 | # primo target: gli eseguibili sono precondizioni 22 | # quindi verranno tutti creati 23 | all: $(EXECS) 24 | 25 | 26 | pctestCV.o: pctest.c xerrori.h 27 | $(CC) $(CFLAGS) -c $< -DUSACV -o $@ 28 | 29 | 30 | # regola per la creazione degli eseguibili utilizzando xerrori.o 31 | %.out: %.o xerrori.o 32 | $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) 33 | 34 | # regola per la creazione di file oggetto che dipendono da xerrori.h 35 | %.o: %.c xerrori.h 36 | $(CC) $(CFLAGS) -c $< 37 | 38 | 39 | # esempio di target che non corrisponde a una compilazione 40 | # ma esegue la cancellazione dei file oggetto e degli eseguibili 41 | clean: 42 | rm -f *.o $(EXECS) 43 | 44 | # crea file zip della lezione 45 | zip: 46 | zip threads.zip *.c *.h *.py makefile 47 | 48 | -------------------------------------------------------------------------------- /08threads/tabella_primi.c: -------------------------------------------------------------------------------- 1 | #include "xerrori.h" 2 | 3 | // costruzione di una tabella di primi con thread multipli 4 | 5 | // questo programma è stato ottenuto partendo da 6 | // contaprimi.c aggiungendo la gestione di una tabella 7 | 8 | #define QUI __LINE__, __FILE__ 9 | 10 | //Prototipi 11 | bool primo(int n); 12 | 13 | // struct che uso per passare argomenti ai thread 14 | typedef struct { 15 | int start; // intervallo dove cercare i primo 16 | int end; // parametri di input 17 | int somma_parziale; // parametro di output 18 | int *tabella; // tabella dei numeri primi da riempire 19 | int *pmessi; // puntatore a indice in tabella 20 | pthread_mutex_t *pmutex; // mutex condiviso 21 | } dati; 22 | 23 | // funzione passata a pthred_create 24 | void *tbody(void *v) { 25 | dati *d = (dati *) v; 26 | int primi = 0; 27 | // cerco i primi nell'intervallo assegnato 28 | for(int j=d->start;jend;j++) 29 | if(primo(j)) { 30 | primi++; 31 | xpthread_mutex_lock(d->pmutex,QUI); 32 | d->tabella[*(d->pmessi)] = j; 33 | *(d->pmessi) += 1; 34 | xpthread_mutex_unlock(d->pmutex,QUI); 35 | } 36 | fprintf(stderr, "Il thread che partiva da %d ha terminato\n", d->start); 37 | d->somma_parziale = primi; 38 | pthread_exit(NULL); 39 | } 40 | 41 | int main(int argc,char *argv[]) 42 | { 43 | if(argc!=3) { 44 | fprintf(stderr,"Uso\n\t%s m num_threads\n", argv[0]); 45 | exit(1); 46 | } 47 | // conversione input 48 | int m= atoi(argv[1]); 49 | if(m<1) termina("limite primi non valido"); 50 | int p= atoi(argv[2]); 51 | if(p<=0) termina("numero di thread non valido"); 52 | 53 | // definizione mutex 54 | pthread_mutex_t mtabella; 55 | xpthread_mutex_init(&mtabella,NULL,QUI); 56 | // creazione thread ausiliari 57 | pthread_t t[p]; // array di p indentificatori di thread 58 | dati d[p]; // array di p struct che passerò allle p thread 59 | int somma = 0; // variabile dove accumulo il numero di primi 60 | int *tabella = malloc(m*sizeof(int)); 61 | if(tabella==NULL) xtermina("Allocazione fallita", __LINE__, __FILE__); 62 | int messi = 0; 63 | for(int i=0; i // permette di usare scanf printf etc ... 3 | #include // conversioni stringa exit() etc ... 4 | #include // gestisce tipo bool 5 | #include // permette di usare la funzione ass 6 | #include // funzioni per stringhe 7 | #include // richiesto per usare errno 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include /* For mode constants */ 16 | #include /* For O_* constants */ 17 | #include 18 | 19 | // termina programma 20 | void termina(const char *s); 21 | void xtermina(const char *s, int linea, char *file); 22 | 23 | // operazioni su FILE * 24 | FILE *xfopen(const char *path, const char *mode, int linea, char *file); 25 | 26 | // operazioni su file descriptors 27 | void xclose(int fd, int linea, char *file); 28 | 29 | // operazioni su processi 30 | pid_t xfork(int linea, char *file); 31 | pid_t xwait(int *status, int linea, char *file); 32 | // pipes 33 | int xpipe(int pipefd[2], int linea, char *file); 34 | 35 | 36 | // memoria condivisa POSIX 37 | int xshm_open(const char *name, int oflag, mode_t mode, int linea, char *file); 38 | int xshm_unlink(const char *name, int linea, char *file); 39 | int xftruncate(int fd, off_t length, int linea, char *file); 40 | void *simple_mmap(size_t length, int fd, int linea, char *file); 41 | int xmunmap(void *addr, size_t length, int linea, char *file); 42 | 43 | // semafori POSIX 44 | sem_t *xsem_open(const char *name, int oflag, mode_t mode, unsigned int value, int linea, char *file); 45 | int xsem_unlink(const char *name, int linea, char *file); 46 | int xsem_close(sem_t *sem, int linea, char *file); 47 | int xsem_init(sem_t *sem, int pshared, unsigned int value, int linea, char *file); 48 | int xsem_destroy(sem_t *sem, int linea, char *file); 49 | int xsem_post(sem_t *sem, int linea, char *file); 50 | int xsem_wait(sem_t *sem, int linea, char *file); 51 | 52 | // thread 53 | void xperror(int en, char *msg); 54 | 55 | int xpthread_create(pthread_t *thread, const pthread_attr_t *attr, 56 | void *(*start_routine) (void *), void *arg, int linea, char *file); 57 | int xpthread_join(pthread_t thread, void **retval, int linea, char *file); 58 | 59 | // mutex 60 | int xpthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr, int linea, char *file); 61 | int xpthread_mutex_destroy(pthread_mutex_t *mutex, int linea, char *file); 62 | int xpthread_mutex_lock(pthread_mutex_t *mutex, int linea, char *file); 63 | int xpthread_mutex_unlock(pthread_mutex_t *mutex, int linea, char *file); 64 | 65 | // condition variables 66 | int xpthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr, int linea, char *file); 67 | int xpthread_cond_destroy(pthread_cond_t *cond, int linea, char *file); 68 | int xpthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, int linea, char *file); 69 | int xpthread_cond_signal(pthread_cond_t *cond, int linea, char *file); 70 | int xpthread_cond_broadcast(pthread_cond_t *cond, int linea, char *file); 71 | 72 | -------------------------------------------------------------------------------- /09condvar/heap.c: -------------------------------------------------------------------------------- 1 | #include "xerrori.h" 2 | // abbreviamo la chiamata alle funzioni x... 3 | #define QUI __LINE__,__FILE__ 4 | 5 | 6 | // gestione di heap mediante condition variable 7 | // per fare si che le stampe riflettano l'effettivo ordine 8 | // delle operazioni queste sono effettuate quando il 9 | // mutex è sempre bloccato 10 | 11 | // struct che tiene traccia della memoria disponibile e 12 | // contiene le variabili cond/mutex per regolarne l'utilizzo 13 | typedef struct { 14 | pthread_cond_t *cv; // condition variable 15 | pthread_mutex_t *mu; // mutex 16 | int MB; // memoria attualmente disponibile 17 | } heap; 18 | 19 | // simula allocazione con spazio limitato 20 | void richiedi(heap *h, int n) { 21 | xpthread_mutex_lock(h->mu,QUI); 22 | fprintf(stderr,"%2d Richiesti: %3d\n", gettid()%100, n); 23 | while(n>h->MB) { 24 | fprintf(stderr,"%2d Negati: %3d\n", gettid()%100, n); 25 | xpthread_cond_wait(h->cv,h->mu,QUI); 26 | } 27 | h->MB -= n; 28 | fprintf(stderr,"%2d Assegnati: %3d. Rimanenti: %4d\n\n", gettid()%100, 29 | n,h->MB); 30 | xpthread_mutex_unlock(h->mu,QUI); 31 | } 32 | 33 | // deallocazione 34 | void libera(heap *h, int n) { 35 | xpthread_mutex_lock(h->mu,QUI); 36 | h->MB += n; 37 | xpthread_cond_broadcast(h->cv,QUI); 38 | fprintf(stderr,"%2d Restituiti: %3d. Rimanenti: %4d\n\n", gettid()%100, 39 | n,h->MB); 40 | xpthread_mutex_unlock(h->mu,QUI); 41 | } 42 | 43 | 44 | // codice thread tipo 1, chiede 10,20,...,50 45 | void *tipo1(void *v) { 46 | heap *h = (heap *) v; 47 | for(int i=1;i<=5;i++) { 48 | int m = 10*i; 49 | richiedi(h,m); 50 | sleep(1); 51 | libera(h,m); 52 | } 53 | return NULL; 54 | } 55 | 56 | // codice thread tipo 2, chiede 15,25,...,55 57 | void *tipo2(void *v) { 58 | heap *h = (heap *) v; 59 | for(int i=1;i<=5;i++) { 60 | int m = 10*i+5; 61 | richiedi(h,m); 62 | sleep(1); 63 | libera(h,m); 64 | } 65 | return NULL; 66 | } 67 | 68 | 69 | int main(int argc, char *argv[]) 70 | { 71 | // controlla numero argomenti 72 | if(argc!=3) { 73 | printf("Uso: %s mem numT\n",argv[0]); 74 | return 1; 75 | } 76 | int mem = atoi(argv[1]); 77 | int nt = atoi(argv[2]); 78 | assert(nt>1); 79 | 80 | // inizializza heap 81 | pthread_cond_t c = PTHREAD_COND_INITIALIZER; 82 | pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; 83 | heap h; 84 | h.cv = &c; h.mu = &m; 85 | h.MB = mem; 86 | 87 | // esegue i thread 88 | pthread_t t[nt]; 89 | // esegue un thread tipo1 90 | xpthread_create(&t[0],NULL,&tipo1,&h,QUI); 91 | for(int i=1;i // permette di usare scanf printf etc ... 3 | #include // conversioni stringa exit() etc ... 4 | #include // gestisce tipo bool 5 | #include // permette di usare la funzione ass 6 | #include // funzioni per stringhe 7 | #include // richiesto per usare errno 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include /* For mode constants */ 16 | #include /* For O_* constants */ 17 | #include 18 | 19 | // termina programma 20 | void termina(const char *s); 21 | void xtermina(const char *s, int linea, char *file); 22 | 23 | // operazioni su FILE * 24 | FILE *xfopen(const char *path, const char *mode, int linea, char *file); 25 | 26 | // operazioni su file descriptors 27 | void xclose(int fd, int linea, char *file); 28 | 29 | // operazioni su processi 30 | pid_t xfork(int linea, char *file); 31 | pid_t xwait(int *status, int linea, char *file); 32 | // pipes 33 | int xpipe(int pipefd[2], int linea, char *file); 34 | 35 | 36 | // memoria condivisa POSIX 37 | int xshm_open(const char *name, int oflag, mode_t mode, int linea, char *file); 38 | int xshm_unlink(const char *name, int linea, char *file); 39 | int xftruncate(int fd, off_t length, int linea, char *file); 40 | void *simple_mmap(size_t length, int fd, int linea, char *file); 41 | int xmunmap(void *addr, size_t length, int linea, char *file); 42 | 43 | // semafori POSIX 44 | sem_t *xsem_open(const char *name, int oflag, mode_t mode, unsigned int value, int linea, char *file); 45 | int xsem_unlink(const char *name, int linea, char *file); 46 | int xsem_close(sem_t *sem, int linea, char *file); 47 | int xsem_init(sem_t *sem, int pshared, unsigned int value, int linea, char *file); 48 | int xsem_destroy(sem_t *sem, int linea, char *file); 49 | int xsem_post(sem_t *sem, int linea, char *file); 50 | int xsem_wait(sem_t *sem, int linea, char *file); 51 | 52 | // thread 53 | void xperror(int en, char *msg); 54 | 55 | int xpthread_create(pthread_t *thread, const pthread_attr_t *attr, 56 | void *(*start_routine) (void *), void *arg, int linea, char *file); 57 | int xpthread_join(pthread_t thread, void **retval, int linea, char *file); 58 | 59 | // mutex 60 | int xpthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr, int linea, char *file); 61 | int xpthread_mutex_destroy(pthread_mutex_t *mutex, int linea, char *file); 62 | int xpthread_mutex_lock(pthread_mutex_t *mutex, int linea, char *file); 63 | int xpthread_mutex_unlock(pthread_mutex_t *mutex, int linea, char *file); 64 | 65 | // condition variables 66 | int xpthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr, int linea, char *file); 67 | int xpthread_cond_destroy(pthread_cond_t *cond, int linea, char *file); 68 | int xpthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, int linea, char *file); 69 | int xpthread_cond_signal(pthread_cond_t *cond, int linea, char *file); 70 | int xpthread_cond_broadcast(pthread_cond_t *cond, int linea, char *file); 71 | 72 | -------------------------------------------------------------------------------- /09condvar/zem.c: -------------------------------------------------------------------------------- 1 | #include "xerrori.h" 2 | #define QUI __LINE__,__FILE__ 3 | 4 | 5 | // Realizzazione di un semaforo usando mutex+condition variable 6 | 7 | // il semaforo blocca solo sullo 0 mentre 8 | // con una condition variable abbiamo visto che ci si può 9 | // bloccare su condizioni più complesse, quindi è più generale 10 | 11 | // un semaforo si può realizzare con mutex + condition var 12 | // come mostrato qui sotto. Notate che otteniamo un semaforo 13 | // che supporta incrementi e decrementi anche maggiori di 1 14 | 15 | 16 | // struttura rappresentante il semaforo 17 | typedef struct { 18 | int tot; // valore del semaforo, non deve mai diventare negativo 19 | pthread_cond_t cond; // condition variable 20 | pthread_mutex_t mutex; // mutex associato alla condition variable 21 | } zem; 22 | 23 | 24 | // inzializza semaforo al valore q 25 | // deve essere chiamata (una volta sola!) prima di up e down 26 | void zem_init(zem *z, int q) 27 | { 28 | assert(q>=0); 29 | z->tot = q; 30 | xpthread_cond_init(&z->cond,NULL,QUI); 31 | xpthread_mutex_init(&z->mutex,NULL,QUI); 32 | } 33 | 34 | // analoga alla sem_wait (operazione P di Dijkstra) 35 | void zem_down(zem *z, int q) 36 | { 37 | assert(q>0); 38 | pthread_mutex_lock(&z->mutex); 39 | while(z->tot-q<0) 40 | pthread_cond_wait(&z->cond,&z->mutex); 41 | z->tot -= q; 42 | pthread_mutex_unlock(&z->mutex); 43 | } 44 | 45 | // analoga alla sem_post (operazione V di Dijkstra) 46 | void zem_up(zem *z, int q) 47 | { 48 | assert(q>0); 49 | pthread_mutex_lock(&z->mutex); 50 | z->tot+=q; 51 | pthread_cond_broadcast(&z->cond); 52 | pthread_mutex_unlock(&z->mutex); 53 | } 54 | -------------------------------------------------------------------------------- /10signals/MTSafety.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Laboratorio2B/2324-Lab2B/8000dd55ee0b9a79c6ad8dd690457f398e53e19a/10signals/MTSafety.pdf -------------------------------------------------------------------------------- /10signals/makefile: -------------------------------------------------------------------------------- 1 | # definizione del compilatore e dei flag di compilazione 2 | # che vengono usate dalle regole implicite 3 | CC=gcc 4 | CFLAGS=-std=c11 -Wall -g -O -pthread 5 | LDLIBS=-lm -lrt -pthread 6 | 7 | 8 | # su https://www.gnu.org/software/make/manual/make.html#Implicit-Rules 9 | # sono elencate le regole implicite e le variabili 10 | # usate dalle regole implicite 11 | 12 | # Variabili automatiche: https://www.gnu.org/software/make/manual/make.html#Automatic-Variables 13 | # nei comandi associati ad ogni regola: 14 | # $@ viene sostituito con il nome del target 15 | # $< viene sostituito con il primo prerequisito 16 | # $^ viene sostituito con tutti i prerequisiti 17 | 18 | # elenco degli eseguibili da creare 19 | EXECS=segnali.out sigwait.out segnaliT.out segnaliRT.out 20 | 21 | # primo target: gli eseguibili sono precondizioni del target 22 | # quindi verranno tutti creati 23 | all: $(EXECS) 24 | 25 | 26 | # regola per la creazioni degli eseguibili utilizzando xerrori.o 27 | %.out: %.o xerrori.o 28 | $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) 29 | 30 | # regola per la creazione di file oggetto che dipendono da xerrori.h 31 | %.o: %.c xerrori.h 32 | $(CC) $(CFLAGS) -c $< 33 | 34 | # esempio di target che non corrisponde a una compilazione 35 | # ma esegue la cancellazione dei file oggetto e degli eseguibili 36 | clean: 37 | rm -f *.o $(EXECS) 38 | 39 | 40 | -------------------------------------------------------------------------------- /10signals/segnali.c: -------------------------------------------------------------------------------- 1 | #include "xerrori.h" 2 | #define QUI __LINE__,__FILE__ 3 | 4 | // esempio base di gestione segnali con handler 5 | 6 | 7 | // variabili globali utilizzate da main e dal signal handler 8 | int tot_segnali = 0; 9 | // il perche' della keyword volatile lo abbiamo visto a lezione 10 | volatile bool continua = true; 11 | 12 | 13 | // funzione che viene invocata quando viene ricevuto 14 | // un segnale USR1 USR2 o INT (Control-C) 15 | void handler(int s) 16 | { 17 | tot_segnali++; 18 | if(s!=SIGUSR1) { 19 | kill(getpid(),SIGUSR1); // manda SIGUSR1 a se stesso 20 | } 21 | printf("Segnale %d ricevuto dal processo %d\n", s, getpid()); 22 | if(s==SIGUSR2) { 23 | // forza uscita dal loop infinito del main() 24 | continua = false; 25 | } 26 | 27 | } 28 | 29 | 30 | int main(int argc, char *argv[]) 31 | { 32 | // definisce signal handler 33 | struct sigaction sa; 34 | sa.sa_handler = &handler; 35 | // setta sa.sa_mask che è la maschera di segnali da bloccare 36 | // durante l'esecuzione di handler(). Blocca tutti i segnali 37 | sigfillset(&sa.sa_mask); 38 | sigdelset(&sa.sa_mask,SIGUSR1); // tranne SIGUSR1 39 | sigaction(SIGUSR1,&sa,NULL); // handler per USR1 40 | sigaction(SIGUSR2,&sa,NULL); // stesso handler per USR2 41 | // definisco variabile dove salvo il settaggio attuale per SIGINT 42 | struct sigaction oldsa; 43 | sigaction(SIGINT,&sa,&oldsa); // stesso handler per Control-C 44 | 45 | 46 | // visualizza il pid 47 | printf("Se vuoi mandarmi dei segnali il mio pid e': %d\n", getpid()); 48 | 49 | // entra in orribile busy waiting attendendo i segnali 50 | continua = true; 51 | do { // loop apparentemente senza uscita 52 | ; 53 | // scommentare sleep() o pause() per evitare il busy waiting 54 | // sleep(1000); 55 | pause(); 56 | puts("Mi sono svegliato"); 57 | } while(continua); 58 | printf("Ricevuti: %d segnali\n", tot_segnali); 59 | // rimetti la vecchia gestione di SIGINT 60 | sigaction(SIGINT,&oldsa,NULL); 61 | // ora SIGINT interrompe l'esecuzione come per default 62 | puts("Vecchio SIGINT ripristinato"); 63 | 64 | // rientro nel loop, per uscire serve un altro segnale usr2 65 | // oppure un SIGINT.... 66 | continua = true; 67 | do { // loop apparentemente senza uscita 68 | pause(); 69 | } while(continua); 70 | printf("Ricevuti: %d segnali (secondo loop)\n", tot_segnali); 71 | return 0; 72 | } 73 | 74 | -------------------------------------------------------------------------------- /10signals/segnaliRT.c: -------------------------------------------------------------------------------- 1 | #include "xerrori.h" 2 | #define QUI __LINE__,__FILE__ 3 | 4 | // esempio di invio di segnali real-time e di 5 | // invio di una informazione insieme al segnale. 6 | // l'informazione (un int) è memorizzata in una union 7 | 8 | // Per leggere l'informazione la sigwait è rimpiazzata da sigwaitinfo 9 | // è possibile leggere l'informazione del segnale anche usando il campo 10 | // sa_sigaction quando si chiama sigaction() 11 | 12 | 13 | // thread nullafacente 14 | void *tbody(void *v) { 15 | while(true) { 16 | pause(); 17 | printf("====== Thread :%d svegliato\n",gettid()); 18 | } 19 | return NULL; 20 | } 21 | 22 | // thread che effettua la gestione di tutti i segnali 23 | // usa sigwaitinfo per leggere l'informazione associata ai segnali 24 | void *tgestore(void *v) { 25 | sigset_t mask; 26 | sigfillset(&mask); 27 | int s; 28 | siginfo_t sinfo; 29 | while(true) { 30 | int e = sigwaitinfo(&mask,&sinfo); 31 | if(e<0) perror("Errore sigwaitinfo"); 32 | s = sinfo.si_signo; 33 | printf("Thread %d ricevuto segnale %d da %d",gettid(),s,sinfo.si_pid); 34 | printf(" con valore %d\n",sinfo.si_value.sival_int); 35 | if (s == SIGUSR2) { 36 | // manda a se stesso un misto di segnali real-time e standard 37 | // possibilemente con valore associato al segnale 38 | union sigval v; // union inviata al gestore di segnali 39 | 40 | v.sival_int = 1; // invio l'intero 1 insieme al segnale 41 | e = pthread_sigqueue(pthread_self(), SIGINT, v); 42 | if (e != 0) xperror(e, "errore pthread_sigqueue"); 43 | 44 | v.sival_int++; // invio l'intero 2 45 | e = pthread_sigqueue(pthread_self(), SIGRTMAX, v); 46 | if (e != 0) xperror(e, "errore pthread_sigqueue"); 47 | 48 | v.sival_int++; // invio 3, 4, etc etc 49 | e = pthread_sigqueue(pthread_self(), SIGRTMIN, v); 50 | if (e != 0) xperror(e, "errore pthread_sigqueue"); 51 | 52 | v.sival_int++; 53 | // nota: raise(SIGINT) equivalente a pthread_kill(pthread_self(),SIGINT); 54 | e = raise(SIGRTMIN); // questo segnale non ha un valore associato, a me appare 0 55 | if (e != 0) perror("errore raise"); // raise salva errore in errno 56 | 57 | v.sival_int++; // questo segnale viene perso perché è un secondo SIGINT 58 | e = pthread_sigqueue(pthread_self(), SIGINT, v); 59 | if (e != 0) xperror(e, "errore pthread_sigqueue"); 60 | 61 | v.sival_int++; 62 | e = pthread_sigqueue(pthread_self(), SIGRTMAX, v); 63 | if (e != 0) xperror(e, "errore pthread_sigqueue"); 64 | 65 | v.sival_int++; 66 | // e = sigqueue(getpid(), SIGRTMIN + 1, v); // in questo modo mando il segnale con sigqueue() 67 | // if (e != 0) perror("errore sigqueue"); // sigqueue salva errore in errno 68 | e = pthread_sigqueue(pthread_self(), SIGRTMIN+1, v); 69 | if (e != 0) xperror(e, "errore pthread_sigqueue"); 70 | 71 | // è l'ultimo segnale inviato ma verrà gestito prima di tutti i real time 72 | v.sival_int++; 73 | e = pthread_sigqueue(pthread_self(), SIGUSR1, v); 74 | if (e != 0) xperror(e, "errore pthread_sigqueue"); 75 | 76 | 77 | } 78 | } 79 | return NULL; 80 | } 81 | 82 | 83 | int main (void) { 84 | // blocco i segnali tranne SIGQUIT 85 | sigset_t mask; 86 | sigfillset(&mask); // insieme di tutti i segnali 87 | sigdelset(&mask,SIGQUIT); // elimino sigquit dall'insieme 88 | pthread_sigmask(SIG_BLOCK,&mask,NULL); // blocco tutto tranne sigquit 89 | 90 | // creo nuovi thread che ereditano i settaggi dei segnali 91 | pthread_t t[3]; 92 | xpthread_create(&t[0],NULL,tbody,NULL,QUI); // thread nullafacenti 93 | xpthread_create(&t[1],NULL,tbody,NULL,QUI); 94 | xpthread_create(&t[2],NULL,tgestore,NULL,QUI); // thread gestore segnali 95 | 96 | while(true) { 97 | sleep(40); 98 | puts("Main svegliato"); 99 | } 100 | return 0 ; 101 | } 102 | 103 | -------------------------------------------------------------------------------- /10signals/sigwait.c: -------------------------------------------------------------------------------- 1 | #include "xerrori.h" 2 | #define QUI __LINE__,__FILE__ 3 | 4 | // esempio base gestione segnali con 5 | // un thread dedicato e la funzione sigwait 6 | 7 | 8 | // struct contenente i dati condivisi con il thread 9 | // che gestisce i segnali 10 | typedef struct { 11 | int tot_segnali; 12 | bool continua; 13 | } dati; 14 | 15 | // thread che gestisce i segnali 16 | void *gbody(void *arg) { 17 | // recupera argomento passato al thread 18 | dati *d = (dati *) arg; 19 | // si mette in attesa di tutti i segnali 20 | sigset_t mask; 21 | sigfillset(&mask); 22 | sigdelset(&mask,SIGINT); // elimino sigint da mask 23 | // con sigwait gestisco tutti i segnali tranne SIGINT 24 | int s; 25 | while(true) { 26 | // è buona pratica che i segnali in mask siano bloccati 27 | int e = sigwait(&mask,&s); 28 | if(e!=0) perror("Errore sigwait"); 29 | printf("Thread gestore svegliato dal segnale %d\n",s); 30 | d->tot_segnali++; 31 | if(s==SIGUSR2) { 32 | // forza uscita dal loop infinito del main() 33 | d->continua = false; 34 | } 35 | } 36 | return NULL; 37 | } 38 | 39 | 40 | int main(int argc, char *argv[]) 41 | { 42 | // blocco tutti i segnali 43 | sigset_t mask; 44 | sigfillset(&mask); // insieme di tutti i segnali 45 | sigdelset(&mask,SIGQUIT); // elimino sigquit da mask 46 | pthread_sigmask(SIG_BLOCK,&mask,NULL); // blocco tutto tranne sigquit 47 | // non avere bloccato SIGQUIT mi permette di terminare il programma con Control-backslash 48 | 49 | // visualizza il pid 50 | printf("Se vuoi mandarmi dei segnali il mio pid e': %d\n", getpid()); 51 | 52 | // inizializza dati 53 | dati d; 54 | d.tot_segnali = 0; 55 | d.continua = true; 56 | // lancia thread gestore 57 | pthread_t gestore; 58 | xpthread_create(&gestore, NULL, &gbody, &d,QUI); 59 | 60 | do { // loop apparentemente senza uscita 61 | sleep(20); 62 | puts("Mi sono svegliato"); 63 | } while(d.continua); 64 | printf("Ricevuti: %d segnali\n", d.tot_segnali); 65 | return 0; 66 | } 67 | 68 | 69 | -------------------------------------------------------------------------------- /10signals/xerrori.h: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE // permette di usare estensioni GNU 2 | #include // permette di usare scanf printf etc ... 3 | #include // conversioni stringa exit() etc ... 4 | #include // gestisce tipo bool 5 | #include // permette di usare la funzione ass 6 | #include // funzioni per stringhe 7 | #include // richiesto per usare errno 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include /* For mode constants */ 16 | #include /* For O_* constants */ 17 | #include 18 | 19 | // termina programma 20 | void termina(const char *s); 21 | void xtermina(const char *s, int linea, char *file); 22 | 23 | // operazioni su FILE * 24 | FILE *xfopen(const char *path, const char *mode, int linea, char *file); 25 | 26 | // operazioni su file descriptors 27 | void xclose(int fd, int linea, char *file); 28 | 29 | // operazioni su processi 30 | pid_t xfork(int linea, char *file); 31 | pid_t xwait(int *status, int linea, char *file); 32 | // pipes 33 | int xpipe(int pipefd[2], int linea, char *file); 34 | 35 | 36 | // memoria condivisa POSIX 37 | int xshm_open(const char *name, int oflag, mode_t mode, int linea, char *file); 38 | int xshm_unlink(const char *name, int linea, char *file); 39 | int xftruncate(int fd, off_t length, int linea, char *file); 40 | void *simple_mmap(size_t length, int fd, int linea, char *file); 41 | int xmunmap(void *addr, size_t length, int linea, char *file); 42 | 43 | // semafori POSIX 44 | sem_t *xsem_open(const char *name, int oflag, mode_t mode, unsigned int value, int linea, char *file); 45 | int xsem_unlink(const char *name, int linea, char *file); 46 | int xsem_close(sem_t *sem, int linea, char *file); 47 | int xsem_init(sem_t *sem, int pshared, unsigned int value, int linea, char *file); 48 | int xsem_destroy(sem_t *sem, int linea, char *file); 49 | int xsem_post(sem_t *sem, int linea, char *file); 50 | int xsem_wait(sem_t *sem, int linea, char *file); 51 | 52 | // thread 53 | void xperror(int en, char *msg); 54 | 55 | int xpthread_create(pthread_t *thread, const pthread_attr_t *attr, 56 | void *(*start_routine) (void *), void *arg, int linea, char *file); 57 | int xpthread_join(pthread_t thread, void **retval, int linea, char *file); 58 | 59 | // mutex 60 | int xpthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr, int linea, char *file); 61 | int xpthread_mutex_destroy(pthread_mutex_t *mutex, int linea, char *file); 62 | int xpthread_mutex_lock(pthread_mutex_t *mutex, int linea, char *file); 63 | int xpthread_mutex_unlock(pthread_mutex_t *mutex, int linea, char *file); 64 | 65 | // condition variables 66 | int xpthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr, int linea, char *file); 67 | int xpthread_cond_destroy(pthread_cond_t *cond, int linea, char *file); 68 | int xpthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, int linea, char *file); 69 | int xpthread_cond_signal(pthread_cond_t *cond, int linea, char *file); 70 | int xpthread_cond_broadcast(pthread_cond_t *cond, int linea, char *file); 71 | 72 | -------------------------------------------------------------------------------- /11sockets/cserver.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Laboratorio2B/2324-Lab2B/8000dd55ee0b9a79c6ad8dd690457f398e53e19a/11sockets/cserver.pdf -------------------------------------------------------------------------------- /11sockets/echo-client.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # echo-client.py 3 | 4 | 5 | # esempio di un client che si connette a echo-server.py 6 | 7 | 8 | import sys,socket 9 | 10 | # valori di default verso cui connettersi 11 | HOST = "127.0.0.1" # The server's hostname or IP address 12 | PORT = 65432 # The port used by the server 13 | 14 | # esegue una singola connessione verso host sulla porta port 15 | def main(host=HOST,port=PORT): 16 | print(f"Mi collego a {host} sulla porta {port}") 17 | # creazione del socket per la connesssione al server 18 | with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: 19 | s.connect((host, port)) 20 | while True: 21 | n = int(input("Quanti byte? ")) 22 | if n<=0: 23 | break 24 | # invio stringa di n 'a' e attendo la risposta 25 | msg = "a"*n 26 | # converte il messaggio in sequenza di byte 27 | s.sendall(msg.encode()) 28 | data = s.recv(64) 29 | print(f"Ricevuto {data}, bytes: {len(data)}") 30 | if len(data)==0: 31 | break 32 | # all'uscita dal blocco with viene eseguito s.close() 33 | # ma per uscire in maniera più pulita dobbiamo 34 | # usare prima anche shutdown() 35 | # SHUT_RDWR indica che terminiamo sia lettura che scrittura 36 | s.shutdown(socket.SHUT_RDWR) 37 | 38 | 39 | 40 | # invoca il main con i parametri passati sulla linea di comando 41 | # oppure con HOST e PORT di default 42 | if len(sys.argv)==1: 43 | main() 44 | elif len(sys.argv)==2: 45 | main(sys.argv[1]) 46 | elif len(sys.argv)==3: 47 | main(sys.argv[1], int(sys.argv[2])) 48 | else: 49 | print("Uso:\n\t %s [host] [port]" % sys.argv[0]) 50 | 51 | -------------------------------------------------------------------------------- /11sockets/echo-server.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # echo-server.py 3 | 4 | 5 | # esempio di un server che si mette in attesa 6 | # su di un socket e quando inizia una connessione 7 | # si limita a rispedire ogni messaggio che ha ricevuto 8 | 9 | import socket 10 | 11 | # specifica da dove accettare le connessioni 12 | HOST = "127.0.0.1" # Standard loopback interface address (localhost) 13 | PORT = 65432 # Port to listen on (non-privileged ports are > 1023) 14 | 15 | # creazione del server socket 16 | with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: 17 | # permette di riutilizzare la porta se il server viene chiuso 18 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 19 | # metto in ascolto il server sulla porta specificata 20 | s.bind((HOST, PORT)) 21 | # il server si mette in attesa di connessioni 22 | s.listen() 23 | while True: 24 | print(f"In attesa di un client su porta {PORT}...") 25 | # mi metto in attesa di una connessione 26 | conn, addr = s.accept() 27 | # lavoro con la connessione appena ricevuta 28 | with conn: 29 | print(f"Contattato da {addr}") 30 | while True: 31 | data = conn.recv(64) # leggo fino a 64 bytes 32 | print(f"Ricevuti {len(data)} bytes") 33 | if not data: # se ricevo 0 bytes 34 | break # la connessione è terminata 35 | conn.sendall(data) # altrimenti invio i dati ricevuti 36 | print("Connessione terminata") 37 | 38 | -------------------------------------------------------------------------------- /11sockets/makefile: -------------------------------------------------------------------------------- 1 | # definizione del compilatore e dei flag di compilazione 2 | # che vengono usate dalle regole implicite 3 | CC=gcc 4 | CFLAGS=-g -Wall -O -std=c99 5 | LDLIBS=-lm -lrt -pthread 6 | 7 | EXEC=pclient.out 8 | 9 | # se si scrive solo make di default compila main 10 | all: $(EXEC) 11 | 12 | %.out: %.o 13 | $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) 14 | 15 | 16 | # target che cancella eseguibili e file oggetto 17 | clean: 18 | rm -f $(EXEC) *.o 19 | 20 | -------------------------------------------------------------------------------- /11sockets/multipclient.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # multipclient.py 3 | # lancia -t processi client per testare i server concorrenti 4 | 5 | Description ="""Client che manda richieste multiple concorrenti al server dei primi""" 6 | 7 | import struct,socket,argparse,concurrent.futures,os,sys,time 8 | 9 | # default HOST e PORT 10 | HOST = "127.0.0.1" 11 | PORT = 65432 12 | 13 | 14 | def main(a,b,host,port): 15 | # inizializzazione socket client 16 | with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: 17 | # la prossima chiamata è blocking 18 | s.connect((host, port)) 19 | # print(f"{os.getpid()}: connesso a {s.getpeername()}") 20 | print(f"{os.getpid()}: connesso; richiede {a}-{b}") 21 | # pronto per inviare la richiesta 22 | s.sendall(struct.pack("!2i",a,b)) 23 | # chiedo quanti primi mi verranno restituiti 24 | data = recv_all(s,4) 25 | n = struct.unpack("!i",data)[0] 26 | print(f"{os.getpid()}: devo ricevere {n} primi") 27 | # ricevo i byte di tutti i primi e li decodifico 28 | data = recv_all(s,4*n) 29 | time.sleep(5) 30 | # notare l'uso dell'espressione {n} per convertire n interi 31 | primi = struct.unpack(f"!{n}i",data) 32 | for p in primi: 33 | print(f"{p:>12}",file=sys.stderr) # stampa p right aligned in 12 caratteri 34 | # per controllo restituisce al server la somma dei primi trovati in 64 bit 35 | s.sendall(struct.pack("!q",sum(primi))) 36 | print(f"{os.getpid()}: somma inviata, termino la connessione") 37 | s.shutdown(socket.SHUT_RDWR) 38 | 39 | 40 | # Riceve esattamente n byte dal socket conn e li restituisce 41 | # il tipo restituto è "bytes": una sequenza immutabile di valori 0-255 42 | def recv_all(conn,n): 43 | chunks = b'' 44 | bytes_recd = 0 45 | while bytes_recd < n: 46 | chunk = conn.recv(min(n - bytes_recd, 1024)) 47 | if len(chunk) == 0: 48 | raise RuntimeError("socket connection broken") 49 | chunks += chunk 50 | bytes_recd = bytes_recd + len(chunk) 51 | return chunks 52 | 53 | 54 | # questo codice viene eseguito solo se il file è eseguito direttamente 55 | # e non importato come modulo con import da un altro file 56 | if __name__ == '__main__': 57 | # parsing della linea di comando vedere la guida 58 | # https://docs.python.org/3/howto/argparse.html 59 | parser = argparse.ArgumentParser(description=Description, formatter_class=argparse.RawTextHelpFormatter) 60 | parser.add_argument('min', help='minimo', type = int) 61 | parser.add_argument('max', help='massimo', type = int) 62 | parser.add_argument('-a', help='host address', type = str, default=HOST) 63 | parser.add_argument('-p', help='port', type = int, default=PORT) 64 | parser.add_argument('-t', help='numero processi', type = int, default=1) 65 | args = parser.parse_args() 66 | assert args.t > 0, "Il numero di thread deve essere maggiore di 0" 67 | with concurrent.futures.ProcessPoolExecutor(max_workers=args.t) as executor: 68 | for i in range(args.t): 69 | # attenzione: l'executor non mostra eventuali eccezioni verificate in main() 70 | executor.submit(main,1000*i+args.min,1000*i+args.max,args.a,args.p) 71 | -------------------------------------------------------------------------------- /11sockets/pclient.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | import struct,socket,argparse,os,sys 3 | 4 | 5 | 6 | Description = "Esempio di client python per interrogare il server dei primi" 7 | # default HOST e PORT a cui collegarsi 8 | HOST = "127.0.0.1" 9 | PORT = 65432 10 | 11 | 12 | def main(a,b,host,port): 13 | # inizializzazione socket client 14 | with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: 15 | # la prossima chiamata è blocking 16 | s.connect((host, port)) 17 | print(f"{os.getpid()}: connesso a {s.getpeername()}") 18 | # pronto per inviare la richiesta 19 | s.sendall(struct.pack("!2i",a,b)) 20 | # chiedo quanti primi mi verranno restituiti 21 | data = recv_all(s,4) 22 | n = struct.unpack("!i",data)[0] 23 | print(f"{os.getpid()}: devo ricevere {n} primi") 24 | # ricevo i byte di tutti i primi e li decodifico 25 | data = recv_all(s,4*n) 26 | # notare l'uso dell'espressione {n} per convertire n interi 27 | primi = struct.unpack(f"!{n}i",data) 28 | for p in primi: 29 | print(f"{p:>12}",file=sys.stderr) # stampa p right aligned in 12 caratteri 30 | # per controllo restituisce al server la somma dei primi trovati in 64 bit 31 | s.sendall(struct.pack("!q",sum(primi))) 32 | print(f"{os.getpid()}: somma inviata, termino la connessione") 33 | s.shutdown(socket.SHUT_RDWR) 34 | 35 | 36 | # Riceve esattamente n byte dal socket conn e li restituisce 37 | # il tipo restituto è "bytes": una sequenza immutabile di valori 0-255 38 | def recv_all(conn,n): 39 | chunks = b'' 40 | bytes_recd = 0 41 | while bytes_recd < n: 42 | chunk = conn.recv(min(n - bytes_recd, 1024)) 43 | if len(chunk) == 0: 44 | raise RuntimeError("socket connection broken") 45 | chunks += chunk 46 | bytes_recd = bytes_recd + len(chunk) 47 | return chunks 48 | 49 | 50 | # questo codice viene eseguito solo se il file è eseguito direttamente 51 | # e non importato come modulo con import da un altro file 52 | if __name__ == '__main__': 53 | # parsing della linea di comando vedere la guida 54 | # https://docs.python.org/3/howto/argparse.html 55 | parser = argparse.ArgumentParser(description=Description, formatter_class=argparse.RawTextHelpFormatter) 56 | parser.add_argument('min', help='minimo', type = int) 57 | parser.add_argument('max', help='massimo', type = int) 58 | parser.add_argument('-a', help='host address', type = str, default=HOST) 59 | parser.add_argument('-p', help='port', type = int, default=PORT) 60 | args = parser.parse_args() 61 | main(args.min,args.max,args.a,args.p) 62 | -------------------------------------------------------------------------------- /11sockets/poolpserver.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # server che fornisce l'elenco dei primi in un dato intervallo 3 | # gestisce più clienti contemporaneamente usando i thread 4 | # invia il byte inutile all'inizio della connessione 5 | import sys, struct, socket, threading, concurrent.futures 6 | 7 | 8 | # host e porta di default 9 | HOST = "127.0.0.1" # Standard loopback interface address (localhost) 10 | PORT = 65432 # Port to listen on (non-privileged ports are > 1023) 11 | 12 | 13 | def main(host=HOST,port=PORT): 14 | # creiamo il server socket 15 | with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: 16 | try: 17 | # permette di riutilizzare la porta se il server viene chiuso 18 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 19 | s.bind((host, port)) 20 | s.listen() 21 | with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor: 22 | while True: 23 | print("In attesa di un client...") 24 | # mi metto in attesa di una connessione 25 | conn, addr = s.accept() 26 | # l'esecuzione di submit non è bloccante 27 | # fino a quando ci sono thread liberi 28 | executor.submit(gestisci_connessione, conn,addr) 29 | except KeyboardInterrupt: 30 | pass 31 | print('Va bene smetto...') 32 | s.shutdown(socket.SHUT_RDWR) 33 | 34 | 35 | # gestisci una singola connessione con un client 36 | def gestisci_connessione(conn,addr): 37 | # in questo caso potrei usare direttamente conn 38 | # e l'uso di with serve solo a garantire che 39 | # conn venga chiusa all'uscita del blocco 40 | # ma in generale with esegue le necessarie 41 | # inzializzazioni e il clean-up finale 42 | with conn: 43 | print(f"{threading.current_thread().name} contattato da {addr}") 44 | # ---- attendo due interi da 32 bit, quindi 8 byte in totale 45 | data = recv_all(conn,8) 46 | assert len(data)==8, "Errore ricezione interi" 47 | # ---- decodifico i due interi dal network byte order 48 | inizio = struct.unpack("!i",data[:4])[0] 49 | fine = struct.unpack("!i",data[4:])[0] 50 | print("Ho ricevuto i valori", inizio,fine) 51 | # ---- calcolo elenco dei primi 52 | primi = elenco_primi(inizio, fine) 53 | # ---- invio risultato in formato preceduto da lunghezza 54 | conn.sendall(struct.pack("!i",len(primi))) #lunghezza 55 | for p in primi: 56 | conn.sendall(struct.pack("!i",p)) # singoli valori 57 | # ---- ricevo la somma dei primi trovati 58 | data = recv_all(conn,8) 59 | somma = struct.unpack("!q",data)[0] 60 | if somma == sum(primi): 61 | print(f"Somma corretta ricevuta da {addr}") 62 | print(f"{threading.current_thread().name} finito con {addr}\n") 63 | 64 | 65 | 66 | 67 | # riceve esattamente n byte e li restituisce in un array di byte 68 | # il tipo restituto è "bytes": una sequenza immutabile di valori 0-255 69 | # analoga alla readn che abbiamo visto nel C 70 | def recv_all(conn,n): 71 | chunks = b'' 72 | bytes_recd = 0 73 | while bytes_recd < n: 74 | chunk = conn.recv(min(n - bytes_recd, 1024)) 75 | if len(chunk) == 0: 76 | raise RuntimeError("socket connection broken") 77 | chunks += chunk 78 | bytes_recd = bytes_recd + len(chunk) 79 | return chunks 80 | 81 | 82 | 83 | # restituisce lista dei primi in [a,b] 84 | def elenco_primi(a,b): 85 | ris = [] 86 | for i in range(a,b+1): 87 | if primo(i): 88 | ris.append(i); 89 | return ris 90 | 91 | 92 | # dato un intero n>0 restituisce True se n e' primo 93 | # False altrimenti 94 | def primo(n): 95 | assert n>0, "L'input deve essere positivo" 96 | if n==1: 97 | return False 98 | if n==2: 99 | return True 100 | if n%2 == 0: 101 | return False 102 | assert n>=3 and n%2==1, "C'e' qualcosa che non funziona" 103 | for i in range(3,n//2,2): 104 | # fa attendere solamente questo thread 105 | # threading.Event().wait(.5) 106 | if n%i==0: 107 | return False 108 | if i*i > n: 109 | break 110 | return True 111 | 112 | 113 | 114 | if len(sys.argv)==1: 115 | main() 116 | elif len(sys.argv)==2: 117 | main(sys.argv[1]) 118 | elif len(sys.argv)==3: 119 | main(sys.argv[1], int(sys.argv[2])) 120 | else: 121 | print("Uso:\n\t %s [host] [port]" % sys.argv[0]) 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /11sockets/sommaprimi.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | 3 | import sys, threading, logging, time, os 4 | import concurrent.futures 5 | 6 | # configurazione del logging 7 | # il logger scrive su un file con nome uguale al nome del file eseguibile 8 | logging.basicConfig(filename=os.path.basename(sys.argv[0])[:-3] + '.log', 9 | level=logging.DEBUG, datefmt='%d/%m/%y %H:%M:%S', 10 | format='%(asctime)s - %(levelname)s - %(message)s') 11 | 12 | 13 | 14 | # classe usata per rappresentare la somma e il suo mutex 15 | class Somma: 16 | def __init__(self): 17 | self.somma = 0 18 | self.lock = threading.Lock() # questo è l'analogo di un mutex del C 19 | 20 | 21 | # calcola la somma dei primi in [a,b) 22 | def tbody(a,b,somma): 23 | logging.debug(f"Inizia esecuzione del thread che parte da {a} e arriva a {b}") 24 | lis = elenco_primi(a, b) 25 | for p in lis: 26 | with somma.lock: # equivalente a mutex_lock 27 | tmp = somma.somma + p 28 | time.sleep(0.01) 29 | somma.somma = tmp # mutex_unlock all'uscita dal thread 30 | logging.debug(f"Termina esecuzione del thread che parte da {a} e arriva a {b}") 31 | return 32 | 33 | 34 | # funzione per calcolare la somma dei primi in [a,b] 35 | def main(a,b,p): 36 | logging.debug("Inizia esecuzione di main") 37 | assert p>0, "Il numero di thread deve essere maggiore di 0" 38 | # crea l'intervallo per ognuno dei p thread 39 | somma = Somma() 40 | with concurrent.futures.ThreadPoolExecutor(max_workers=p) as executor: 41 | for i in range(p): 42 | ai = a+(b-a)*i//p 43 | bi = a+(b-a)*(i+1)//p-1 44 | # esempio di uso di submit(): crea un singolo thread 45 | # che esegue la funzione tbody con i parametri ai, bi, somma 46 | executor.submit(tbody, ai, bi, somma) 47 | print(f"La somma dei primi in [{a},{b}) e' {somma.somma}") 48 | logging.debug("Termina esecuzione di main") 49 | return 50 | 51 | 52 | # restituisce lista dei primi in [a,b] 53 | def elenco_primi(a,b): 54 | ris = [] 55 | for i in range(a,b+1): 56 | if primo(i): 57 | ris.append(i); 58 | return ris 59 | 60 | 61 | # dato un intero n>0 restituisce True se n e' primo 62 | # False altrimenti 63 | def primo(n): 64 | assert n>0, "L'input deve essere positivo" 65 | if n==1: 66 | return False 67 | if n==2: 68 | return True 69 | if n%2 == 0: 70 | return False 71 | assert n>=3 and n%2==1, "C'e' qualcosa che non funziona" 72 | for i in range(3,n//2,2): 73 | if n%i==0: 74 | return False 75 | if i*i > n: 76 | break 77 | return True 78 | 79 | 80 | # invoca il main con i parametri passati sulla linea di comando 81 | if len(sys.argv)==3: 82 | main(int(sys.argv[1]), int(sys.argv[2]), 1) 83 | elif len(sys.argv)==4: 84 | main(int(sys.argv[1]), int(sys.argv[2]), int(sys.argv[3])) 85 | else: 86 | print("Uso:\n\t %s inizio fine [numthread]" % sys.argv[0]) 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Materiale didattico per il corso di Laboratorio 2B, Anno Accademico 2023/24 2 | 3 | Questo repository contiene gli esempi di codice fatti a lezione e il registro delle lezioni. Altro materiale utile si trova sul [corso Moodle](https://elearning.di.unipi.it/course/view.php?id=533). 4 | 5 | --------------------------------------------------------------------------------