Anteprima
Vedrai una selezione di 10 pagine su 306
Architettura dei calcolatori e sistemi operativi - Appunti Pag. 1 Architettura dei calcolatori e sistemi operativi - Appunti Pag. 2
Anteprima di 10 pagg. su 306.
Scarica il documento per vederlo tutto.
Architettura dei calcolatori e sistemi operativi - Appunti Pag. 6
Anteprima di 10 pagg. su 306.
Scarica il documento per vederlo tutto.
Architettura dei calcolatori e sistemi operativi - Appunti Pag. 11
Anteprima di 10 pagg. su 306.
Scarica il documento per vederlo tutto.
Architettura dei calcolatori e sistemi operativi - Appunti Pag. 16
Anteprima di 10 pagg. su 306.
Scarica il documento per vederlo tutto.
Architettura dei calcolatori e sistemi operativi - Appunti Pag. 21
Anteprima di 10 pagg. su 306.
Scarica il documento per vederlo tutto.
Architettura dei calcolatori e sistemi operativi - Appunti Pag. 26
Anteprima di 10 pagg. su 306.
Scarica il documento per vederlo tutto.
Architettura dei calcolatori e sistemi operativi - Appunti Pag. 31
Anteprima di 10 pagg. su 306.
Scarica il documento per vederlo tutto.
Architettura dei calcolatori e sistemi operativi - Appunti Pag. 36
Anteprima di 10 pagg. su 306.
Scarica il documento per vederlo tutto.
Architettura dei calcolatori e sistemi operativi - Appunti Pag. 41
1 su 306
D/illustrazione/soddisfatti o rimborsati
Disdici quando
vuoi
Acquista con carta
o PayPal
Scarica i documenti
tutte le volte che vuoi
Estratto del documento

Richiami sui processi in Linux

Tutti i processi hanno un identificatore detto PID (process identifier). Ogni processo tranne init possiede un processo padre (parent).

I programmi (es.: C) sono definiti sequenziali ossia è possibile conoscere l'ordine con cui verranno eseguite le singole istruzioni. Al contrario l'hardware non è sequenziale poiché svolge molti compiti in parallelo mentre si occupa delle singole attività, ossia opera contemporaneamente.

Il sistema operativo gestisce basandosi sull'appoggio dell'hardware varie macchine virtuali che sono definiti come processi. Diversi processi possono coesistere virtualizzati dal s.o, esso normalizza l'hardware in processi sequenziali che sono più semplici da gestire.

Il parallelismo permette quello che si dice multitasking dei programmi.

Un'altra caratteristica di rilievo dei processi dati dal sistema operativo è quella di essere protetto ossia di essere isolato per non subire influenze da parte degli altri processi/programmi.

La nozione di processo che tratteremo qui si riferisce al sistema operativo LINUX ma è analoga per Windows/Mac.

Durante la creazione di un nuovo processo il s.o crea un nuovo PID che è un int intero assegnato dinamicamente.

Un nuovo processo viene SEMPRE creato da un altro processo detto padre, questo processo si dice relazione padre-figlio.

Architettura dei calcolatori - L    1 / 306    25/09/12

Ad esempio in LINUX dopo le operazioni di inizializzazione della macchina il so crea un processo iniziale chiamato init, a sua volta questo si preoccuperà di creare un processo figlio chiamato shell (l'interprete dei comandi) in uno schema che in un processo multiterminale assomiglierebbe al seguente diagramma ad albero:

INIT

  • elaboratore centrale
  • SHELL
  • SHELL
  • SHELL → differenti terminali

La shell è a tutti gli effetti un programma shell.exe che è in grado di creare molti processi figli se riceve il giusto comando di avvio per il lancio di un nuovo eseguibile.

Un processo può eseguire uno ed un solo programma alla volta, se il programma termina o viene terminato il processo muore.

Questo comportamento è analogo a quello a cui siamo abituati quando abbiamo a che fare con un terminale di comando.

In generale la shell è scritta in c e svolge due compiti complementari:

  • aspetta la fine del programma avviato
  • aspetta di ricevere processi paralleli da creare

Esiste dunque un meccanismo di attesa che se un processo termina cerca di riacquisire il controllo dell'interprete di comandi.

Alla terminazione di un processo è possibile trasmettere un codice - terminatore al padre.

Architettura dei calcolatori - L 2 / 306 01/10/12

WAIT

Questa primitiva del sistema operativo é in grado di sospendere l’esecuzione di un processo per attendere la terminazione di un qualsiasi processo figlio.

NB: se il figlio che aspetto é terminato prima che il padre esegua la wait del padre si sblocca subito al momento dell’esecuzione.

Prototipo della funzione wait → pid_t wait(int *)

EXEC

La funzione sostituisce i segmenti codice e dati del processo corrente con quelli di un altro programma specificato tramite pathname, dato che il segmento di sistema non viene sostituito, i file aperti rimangono disponibili. Il processo mantiene lo stesso PID, é inoltre possibile tramite la exec passare parametri al nuovo programma che viene eseguito.

Esistono molte varianti della exec come la execl

Prototipo della funzione execl →

execl (char *nome_programma, char *arg0, char *arg1, ...NULL)

  • nome_programma é una stringa (pathname) del nuovo file eseguibile.
  • arg0, arg1, ... sono puntatori a stringhe che verranno passati al main, l’ultimo puntatore é null per indicare la fine dei parametri.

Architettura dei calcolatori - L

6 / 306

01/10/12

PROGRAMMA THREAD 2 - VARIABILI STATICHE

#include <pthread.h>

#include <stdio.h>

void *tf1(void *tID) { static int conta =0; // conta è una variabile statica conta++; printf("sono thread n: %d; conta = %d \n",(int) tID, conta); return NULL; }

int main(void) { pthread_t tID1; pthread_t tID2; pthread_create(&tID1, NULL, &tf1, (void *)1); pthread_create(&tID2, NULL, &tf1, (void *)2); pthread_join(tID1, NULL); pthread_join(tID2, NULL); return 0; }

Il programma è analogo al precedente ma con conta di tipo static.

Sono thread 1, conta=1 Sono thread 2, conta=2

Oppure con i xx dei thread invertiti.

Questio tipo di comportamento vale per TUTTE le informazioni non contenute sulla pila, le static sono un esempio.

Architettura dei Calcolatori - L 11 / 306 14/10/12

Output

Gli output del programma precedente possono essere pesantemente immessi.

  • a > c b < c e non avviene mai il contrario
  • x < y z < z e non avviene mai il contrario.

Si procede per analizzare le possibili situazioni che possono capitare con il testing che però non può dimostrare con certezza assoluta che un programma sia corretto in quanto dovrebbe dimostrare la validità per qualsiasi configurazione di input. Per quanto il testing non dimostri la correttezza di un programma, nel caso sequenziale costituisce un efficace strumento di verifica.

Gli errori di un programma concorrente non si possono eliminare tramite testing, devono essere preventi attraverso una programmazione particolare ed accurata.

Il modello concorrente è molto usato per programmi in real-time. Dobbiamo quindi avere degli strumenti mentali che ci dicano che siamo abbastanza certi di un comportamento a prescindere dal testing. Per fare questo isoliamo la concorrenza e mostriamo la correttezza di ogni parte sequenziale, dopodiché si dimostra la validità generale tenendo conto della concorrenza. Dunque il testing è necessario ma è utile solo per la parte sequenziale.

Si suppone dunque per analizare il codice che le istruzioni siano serializzabili ossia che anche se a livello macchina le istruzioni si possono mescolare tra loro il risultato sarà ancora di un programma sequenziale.

Istruzioni NON SERIALIZZABILI →

Non sono serializzabili modifiche della stessa variabile basate sul valore della variabile stessa. x = f(x).

Ogni volta che diversi thread modificano la stessa variabile in base al suo valore precedente, bisogna garantive che le operazioni su tale variabile siano sequenze critiche in mutua esclusione.

Questo vale per istruzioni semplice come i++.

In POSIX una soluzione nel garantive il buon funzionamento é data dai MUTEX (mutual exclusion), struttura che mi permette di creare un blocco nell'esecuzione di un determinista sequenza di codice per garantive che altri thread non intervengano. É opportuno utilizzare MUTEX diversi per sequenze critiche #.

Nei pthread si ha {LOCK → blocco UNLOCK → sblocco}

Architettura dei calcolatori - L 21 / 306 14/10/12

Programma esempio utilizzo di un semaforo

#include <semaphore.h> sem_t sem1; sem_t sem2;

void *tf1(void *arg) {

sem_wait(&sem1); printf("x"); sem_post(&sem2); sem_wait(&sem1); printf("y"); sem_post(&sem2); sem_wait(&sem1); printf("z"); return NULL; }

void *tf2(void *arg) { printf("a"); sem_post(&sem1); sem_wait(&sem2); printf("b"); sem_post(&sem1); sem_wait(&sem2); printf("c"); sem_post(&sem1); return NULL; }

int main(void) { pthread_t tID1; pthread_t tID2; sem_init(&sem1, 0, 0); sem_init(&sem2, 0, 0); pthread_create(&tID1, NULL, &tf1, NULL); pthread_create(&tID2, NULL, &tf2, NULL); pthread_join(tID1, NULL); pthread_join(tID2, NULL); printf("\nfine\n"); return 0; }

ESCUZIONE :

  • .axbzcz
  • fine
  • .axbcyz
  • fine

Il programma stampa costantemente alternando i due thread.

Dettagli
Publisher
A.A. 2011-2012
306 pagine
8 download
SSD Scienze matematiche e informatiche INF/01 Informatica

I contenuti di questa pagina costituiscono rielaborazioni personali del Publisher Dolceck di informazioni apprese con la frequenza delle lezioni di Architettura dei calcolatori e sistemi operativi e studio autonomo di eventuali libri di riferimento in preparazione dell'esame finale o della tesi. Non devono intendersi come materiale ufficiale dell'università Politecnico di Milano o del prof Pelegatti Giuseppe.