Nell’ ambito del problema della sincronizzazione di processi, una soluzione che fa a meno di sprecare l'utilizzo della CPU, come nel caso delle variabili di lock, è quella proposta da Dijkstra nel 1965 e che, con qualche modifica, si è imposta nei vari sistemi informatici quasi universalmente (per esempio, è una delle soluzioni adottata sia da Unix che da Windows NT): la soluzione dei semafori. Il semaforo, si rivelò molto utile anche come soluzione a diversi altri problemi simili e più in generale nella sincronizzazione di processi paralleli. Un semaforo è un tipo di oggetto che impiega due operazioni per controllare le sezioni critiche. Un tentativo di entrare in una sezione critica è rappresentabile da una operazione atomica di tipo request (in seguito down), mentre una release (in seguito up) indica un'uscita da essa. L'operazione di up incrementa di uno il valore del semaforo, quella di down lo decrementa della stessa quantità. Se un processo esegue una operazione di down su un semaforo che ha un valore non nullo (cioè maggiore di zero), il suo valore viene decrementato di uno e il processo continua la propria elaborazione; se, al contrario il processo vede che un semaforo è nullo viene messo in stato di attesa (sleep) e vi rimane finché un altro processo esegue un up su quello stesso semaforo. Dal momento che la sincronizzazione tramite semafori è di fatto un tipo di comunicazione tra processi per mezzo di variabili condivise, è importantissimo che ogni operazione di accesso a tali variabili (e quindi sia il test su di esse che la loro modifica) costituisca un'unica azione atomica, cioè una sequenza di istruzioni non interrompibile: se un processo accede o modifica il valore di un certo semaforo, il sistema operativo impedisce (solitamente con una semplice disabilitazione degli interrupt) ad ogni altro processo di fare altrettanto, finché questo non abbia finito e concluso le sue operazioni (compresa anche quella eventuale di ingresso nello stato di sleep), pena l'insuccesso della sincronizzazione. Si può distinguere tra due diversi tipi di semafori:
Semafori binari: che possono assumere solo valore 0 e 1 e sono usati per risolvere i problemi più semplici di mutua esclusione (come il problema della sezione critica);
Semafori contatori: perché possono assumere un valore minore, uguale o maggiore a zero. Per esempio supponendo di avere più istanza di un’ unica risorsa, 5 istanze, si può impostare il semaforo a valore 5. Man mano che ogni istanza viene assegnata ad un processo il valore del semaforo viene decrementato di uno, fino ad arrivare al valore 0 quando tutte le risorse sono in uso.
La programmazione tramite semafori può essere molto difficile e il funzionamento di un sistema che li utilizza è molto sensibile anche ad errori all'apparenza insignificanti ma che in certe condizioni possono portare a situazioni critiche e irrimediabili di stallo (deadlock) dell'intero sistema. Per questo motivo fin dalla metà degli anni settanta sono state proposte da più parti delle soluzioni di più alto livello che costituissero una interfaccia verso la sincronizzazione dei processi capace di rendere più facile la progettazione e la programmazione di sistemi. In particolare Hoare 874) e Brinch Hansen (75) proposero l'impiego di particolari costrutti linguistici d'alto livello, chiamati monitor. Per saperne di più consulta i seguenti approfondimenti:
Tutto quanto riportato in questa pagina è a puro scopo informativo personale. Se non ti trovi in accordo con quanto riportato nella pagina, vuoi fare delle precisazioni, vuoi fare delle aggiunte o hai delle proposte e dei consigli da dare, puoi farlo mandando un email. Ogni indicazione è fondamentale per la continua crescita del sito.