Sezione critica

Da Wikipedia, l'enciclopedia libera.

In informatica, una sezione critica, anche detta regione critica, è una porzione di codice che accede a una risorsa condivisa tra più flussi di esecuzione di un sistema concorrente.

Motivazione[modifica | modifica sorgente]

Quando flussi diversi accedono ad una risorsa in tempi diversi, ognuno di essi può completare la propria operazione (lettura o scrittura) senza essere "disturbato" dagli altri. Se questa condizione vale sempre per una certa risorsa, allora si dice che la lettura e la scrittura su quella risorsa sono operazioni atomiche: ogni flusso può intervenire solo prima o dopo che l'altro ha completato la propria operazione, e non può interromperla. Il termine "atomiche" è inteso nella sua accezione di "unitarie", "indivisibili". Se tutti gli accessi ad una risorsa sono atomici, allora non ci sono problemi di sincronizzazione.

Ad esempio, un programma per la copia di file potrebbe essere implementato con due thread: uno che copia i byte dal disco di origine verso la memoria RAM, e l'altro che contemporaneamente preleva i byte dalla memoria e li scrive nel disco di destinazione. Questo programma ottiene un vantaggio in velocità, perché sovrappone tra loro i tempi di latenza per l'accesso ai dischi, in modo che nessuno dei due risulti bloccato (quindi inutilizzato) a causa dell'altro.

Tuttavia, il sistema operativo non ha consapevolezza del fatto che i flussi di esecuzione si scambiano dei byte: invece, vede solo letture e scritture su dischi e in memoria, e al massimo può garantire che queste operazioni siano singolarmente atomiche. Se i due thread non prevedono la presenza di sezioni critiche, può capitare che essi intervengano contemporaneamente sulla memoria comune, e in particolare può capitare che uno scriva una parte dei dati mentre l'altro li sta ancora leggendo. Il risultato è che il thread che legge "vede" un contenuto in memoria aggiornato solo parzialmente, e quindi leggere informazioni errate. Ciò cambia il comportamento del programma in modo imprevedibile, perché il programmatore non può sapere con quali tempistiche saranno eseguiti i due flussi a tempo di esecuzione.

La soluzione per risolvere il problema è vincolare i due thread ad accedere alla risorsa condivisa sempre e solo in momenti diversi. In gergo, si dice che gli accessi alla risorsa (in lettura e/o in scrittura) si trovano all'interno di sezioni critiche.

Implementazione[modifica | modifica sorgente]

Il modo per definire una sezione critica dipende dal linguaggio di programmazione in uso, tuttavia il meccanismo è generalmente lo stesso: si richiama un meccanismo di sincronizzazione (ad esempio un semaforo) all'entrata ed all'uscita del codice che si vuole nella sezione critica. All'entrata, questo meccanismo controlla il semaforo, per verificare che non vi sia nessun altro processo che sta eseguendo il codice critico. In caso affermativo, l'esecuzione prosegue e il processo corrente prende possesso del semaforo (e quindi della sezione critica), per rilasciarlo all'uscita. In caso contrario, il processo attende che il semaforo si liberi, oppure, nel frattempo, può eseguire un altro compito. L'accesso di più processi ad una sezione critica ha, normalmente, una priorità regolata da una coda FIFO.

Le sezioni critiche sono implementate tipicamente invocando primitive di sistema. Lo svantaggio è che le API di queste primitive dipendono appunto dal sistema, quindi il codice scritto risulta non portabile e va riscritto per i diversi sistemi. Alcuni linguaggi risolvono questo problema fornendo una sintassi unificata per la definizione delle sezioni critiche, in modo da evitare il ricorso a funzioni di sistema (per es. Java).

Il motivo per cui si definiscono sezioni critiche è permettere l'accesso ad una risorsa in mutua esclusione, da parte dei thread che richiedono di leggere o scrivere su tale risorsa. Se viene permesso di accedere alla sezione critica ad un solo processo per volta, allora c'è la garanzia che la risorsa condivisa non venga mai modificata da più processi contemporaneamente, salvando così la consistenza delle informazioni che contiene.

Altre informazioni[modifica | modifica sorgente]

Le sezioni critiche non servono quando il contenuto di una risorsa condivisa è immutabile, ovvero quando nessun flusso di esecuzione è autorizzato a scrivere su quella risorsa.

Infatti, nella programmazione ad oggetti, è noto che gli oggetti immutabili (cioè gli oggetti progettati in modo che non sia consentito cambiarne lo stato interno una volta creati) sono thread-safe, cioè possono essere utilizzati da più flussi di esecuzione senza necessità di ricorrere alle sezioni critiche. Fare uso di oggetti immutabili dovunque possibile rende il codice che li usa più semplice da scrivere e da leggere.[1]

Le condizioni perché una sezione sia effettivamente critica sono 3:
1. mutua esclusione
2. attesa limitata (limite massimo di attesa dopo che ho espresso la volonta' di entrare in sezione critica)
3. progresso (solo chi è fuori dalla propria sezione critica decide chi sara' il prossimo ad entrarci o, in altre parole, chiunque prima o poi deve poter accedere alla propria sezione critica)

Note[modifica | modifica sorgente]

  1. ^ Joshua Bloch, Effective Java, 2ª ed., Pearson Informatica. ISBN 978-88-7192-481-6.
    «Tema 15: Gli oggetti immutabili sono thread-safe in quanto tali e non richiedono alcuna sincronizzazione.».