- 8 -
problematiche che questo tipo di sistemi presentano per la loro realizzazione in un
ambiente multiprocessore.
Un tipo di architettura per i sistemi operativi che si rivelata particolarmente
valida nello sviluppo di sistemi operativi multiprocessore real-time,
l architettura a micro-kernel. Nel capitolo 5 sono discussi i suoi principi,
confrontandoli con quelli della pi tradizionale architettura monolitica, e
mostrando i vantaggi che la prima comporta.
La metodologia di programmazione object-oriented oltre a portare numerosi
benefici in qualunque tipo di applicazione, si presta tra l altro particolarmente
bene ad essere utilizzata nello sviluppo di sistemi operativi a micro-kernel, o
anche semplicemente per l accesso ai loro servizi. Nel capitolo 6 dopo aver
introdotto i suoi concetti fondamentali, sar analizzato come questa possa essere
utilizzata in un ambiente di programmazione concorrente e distribuito,
considerando gli eventuali supporti necessari da parte del sistema operativo.
I concetti e le metodologie fin qui introdotte, sono state quindi utilizzate per
inquadrare e risolvere il problema della creazione di un ambiente multiprocessore
e soft real-time, atto alla realizzazione dell acquisizione dei dati specificati
relativamente all esperimento CHORUS. Nel capitolo 7 sono state introdotte le
caratteristiche dell hardware e del software utilizzati. Dopo avere inquadrato le
caratteristiche di sistema multiprocessore dell hardware, si passati ad una
descrizione del sistema operativo OS-9 utilizzato. La scelta di questo stata in
qualche modo obbligata, nonostante non preveda nessun supporto per i sistemi
multiprocessore. Per risolvere questo problema si implementata un estensione
dei servizi di questo sistema operativo utilizzando un approccio a micro-kernel,
impiegando l OS-9 stesso come micro-kernel aggiungendovi un meccanismo di
comunicazione tra processi funzionante anche tra processori diversi, e un server
chiamato REMOS per la gestione delle risorse condivise tra i vari processori.
Nella realizzazione di ci si inoltre utilizzato la metodologia di
programmazione object-oriented, notando di volta in volta i benefici
relativamente alla possibilit di nascondere all utente i dettagli implementativi, e
alla riusabilit del codice che questo consente di ottenere. In particolare nel
capitolo 8 introdotta un astrazione delle primitive necessarie ad un modello di
comunicazione a memoria comune, che consente di svincolare il loro utilizzo
- 9 -
dalla implementazione, ottenendo di accedere ai servizi equivalenti forniti
dall OS-9 e dal server REMOS, in modo completamente trasparente mediante la
stessa interfaccia. Nello stesso capitolo presentata anche l implementazione OS-
9 di questo modello.
Per poter consentire la richiesta di servizio da parte dei vari processi al server
REMOS, si sviluppato un meccanismo di comunicazione tra i processi
funzionante anche tra processori diversi. Tale meccanismo documentato nel
capitolo 9.
I servizi forniti dal server REMOS sono descritti nel capitolo 10, dove sono
anche analizzate alcune delle problematiche relative all assegnazione delle
priorit ai vari processi, per ottenere le massime prestazioni dal sistema.
Il lavoro descritto fino a questo punto realizza la gestione delle primitive
necessarie al funzionamento del sistema in un ambiente multiprocessore. Il passo
finale, contenuto nel capitolo 11, l implementazione del modello di
comunicazione a memoria comune utilizzando i servizi di REMOS.
Nel capitolo 12 si fornita una misurazione delle prestazioni del sistema in
alcune configurazioni di utilizzo particolarmente significative. Questo tipo di
misure hanno consentito di verificare che il meccanismo di scambio di messaggi,
implementato per la comunicazione tra i vari processori presenti nel sistema, ha
conservato le caratteristiche soft real-time del sistema operativo OS-9.
Nel capitolo 13 si infine introdotta una classe che consente di realizzare un
modello di comunicazione mediante scambio di messaggi, e che utilizza nella sua
implementazione esclusivamente il modello di comunicazione a memoria comune
introdotto. Tale classe stata efficacemente utilizzata nello sviluppo del software
dell acquisizione dati dell esperimento in questione.
- 10 -
2. L ESPERIMENTO CHORUS
Scopo dell esperimento CHORUS al CERN (European Organization for
Nuclear Research - Ginevra) la determinazione dell eventuale massa dei
neutrini. Vi sono tre tipi di neutrini e, se questi avessero massa, potrebbero
cambiare di tipo da uno all altro, o come si dice oscillare. Di conseguenza
l osservazione dell oscillazione di neutrini sarebbe un modo indiretto per
determinare la loro massa. Nell esperimento CHORUS, si analizza l interazione di
un raggio di puri neutrini ν
µ
, generato dall acceleratore SPS al CERN, per
ricercare la presenza di neutrini ν
τ
. L osservazione della loro presenza sarebbe un
segno dell oscillazione dei neutrini e porterebbe alla determinazione della loro
massa [21].
2.1 Composizione e requisiti del sistema d’acquisizione
dati
Il sistema d’acquisizione dati (data acquisition system - DAQ) si compone di
vari rivelatori, ognuno dei quali per ogni evento fisico individuato accumula nel
proprio hardware una certa quantit di dati. Per ciascuno di questi eventi, i dati
presenti nell’hardware di ogni rivelatore devono essere letti, riorganizzati,
eventualmente compressi ed infine registrati su nastro e/o su disco [22].
Senza entrare nei dettagli della struttura dei rivelatori di questo esperimento,
basti sapere che possono essere raggruppati, per scomporre il sistema
d’acquisizione dati, in quattro parti: Trigger (TRIG), Optoelectronics (OPTO),
Calorimiter (CALO) e Spectometer (SPEC). Ciascuno di queste pu essere a sua
volta scomposto, se la complessit dei corrispondenti rivelatori lo richiede. In
particolare l’OPTO ha 29 sottosistemi chiamati genericamente OPTO
i
e lo SPEC
ha un sottosistema Tubes (TUBE).
Ø presente inoltre un altro sottosistema detto Event Builder (EVB), non
corrispondente a nessun rivelatore ma con la funzione di coordinare tutta
l’acquisizione.
- 11 -
EVB
TRIG OPTO CALO SPEC
TUBEOPTO1 OPTO29
Figura A. Organizzazione in sottosistemi del sistema d’acquisizione dati
L’organizzazione del sistema d’acquisizione dati di tipo gerarchico: l’EVB
comunica con i sottosistemi TRIG, OPTO, CALO e SPEC ma non vi
comunicazione diretta tra questi. Ciascuno di questi segue lo stesso modello per la
comunicazione con i suoi sottosistemi. In definitiva si realizza una struttura ad
albero come illustrato in figura a, dove le linee tratteggiate si riferiscono al flusso
di messaggi di controllo, e quelle continue al flusso di messaggi di controllo e di
dati. Ciascun sottosistema comunica direttamente con il sottosistema che nella
scala gerarchica immediatamente superiore e con quelli che sono
immediatamente inferiori, ma non con gli altri.
La presa dati determinata dalla struttura temporale del fascio di neutrini. In
particolare l acceleratore SPS ha un ciclo di 14.4 s durante il quale avvengono due
estrazioni distanziate di 2.8 s. Per ciascuna di queste in ciascun sottosistema si
desidera prendere dati per un certo numero di eventi, come mostrato in tabella a. Il
numero di eventi determinato da limitazioni hardware; il software dovr essere
sufficientemente veloce da non imporre ulteriori limiti.
Sottosistema n. eventi per
estrazione
dimensione dati evento
nell hardware
dimensione dati evento
dopo la compressione
TRIG 50 ~ 1 KB ~ 1 KB
OPTO 2 ~ 2 MB (distribuiti in
ciascuno dei suoi
sottosistemi)
~ 400 KB
CALO 50 ~ 2.5 KB ~ 1 KB
SPEC 5 ~ 22 KB ~ 3 KB
Tabella A. Caratteristiche degli eventi
- 12 -
Sebbene questi requisiti siano alquanto approssimativi, danno comunque
un idea dell ordine di grandezza dei dati che si dovranno trattare e soprattutto di
come il sottosistema critico sia l OPTO, a causa della notevole mole di dati.
- 13 -
3. I SISTEMI MULTIPROCESSORE
Uno dei principali metodi per aumentare le prestazioni di un sistema
d elaborazione dati, quello di aumentare il numero di processori che questo
prevede, distribuendo fra di essi il carico computazionale.
Originariamente questo problema stato affrontato in due modi diversi, che
hanno portato allo sviluppo di tecniche per la gestione di sistemi paralleli e sistemi
distribuiti. Un sistema parallelo un sistema in cui si hanno vari processori
strettamente collegati tra di loro, e che condividono la maggior parte delle risorse
presenti. Un sistema distribuito invece un sistema in cui si hanno varie unit
elaborative, indipendenti tra di loro ma collegate tramite una qualche rete [1, 3].
Lo sviluppo di sistemi paralleli costituiti da un elevato numero di processori,
che comunicano tra di loro esclusivamente tramite lo scambio messaggi come
accade su una rete, e il progressivo miglioramento delle prestazioni delle reti
utilizzate per la comunicazione tra le macchine in un sistema distribuito, ha
portato ad una convergenza tra questi due diversi approcci. Parleremo quindi
genericamente di sistemi multiprocessore, tenendo comunque presente la diversit
realizzativa evidenziata.
3.1 Caratterizzazione dei sistemi multiprocessore
I sistemi multiprocessore possono essere caratterizzati in base
all accoppiamento tra la memoria e i processori.
Nei sistemi multiprocessore a memoria condivisa, la memoria presente
accessibile dai vari processori. Questi sistemi possono essere a loro volta
caratterizzati in base ai tempi di accesso alla memoria stessa.
• Nei sistemi multiprocessore a tempi di accesso uniforme per la memoria
(Uniform Memory Access - UMA), i tempi di accesso alla memoria sono
uguali per tutti i processori. Questa architettura pu essere realizzata
semplicemente collegando i vari processori e la memoria presente nel
sistema tramite un unico bus. In presenza di un numero elevato di
processori, per ridurre i tempi di accesso alla memoria che crescono a causa
delle contese per l accesso al bus, si possono aggiungere delle cache locali
- 14 -
che rendono per di fatto i tempi d acceso non uniformi. Un esempio di
questo tipo di sistema in figura b.
CPU CPU
RAM RAM
Figura B. Esempio di sistema UMA
• Nei sistemi multiprocessore a tempi di accesso non uniforme per la
memoria (Non-Uniform Memory Access - NUMA), i tempi di accesso a
ciascun elemento di memoria variano a seconda del processore. In questa
architettura ogni processore ha la sua memoria locale alla quale collegato
direttamente. Per consentire l accesso alla memoria appartenente ad un altro
processore, vi sar un qualche collegamento, formato ad esempio da un
insieme di bus che unir tra di loro i vari moduli di memoria. Il tempo di
accesso alla memoria di un altro processore risulter quindi essere maggiore
di quello relativo alla memoria locale, e varier a seconda della distanza
alla quale questa si trova. Sono sistemi che in termini di scalabilit pongono
meno problemi degli UMA. Un esempio di questo tipo di sistema in figura
c.
CPU
RAM
Interfaccia
CPU
RAM
Interfaccia
Figura C. Esempio di sistema NUMA
Nei sistemi multiprocessore senza memoria condivisa (NO Remote Memory
Access - NORMA), ogni processore ha la sua memoria locale, che non pu essere
- 15 -
direttamente acceduta dagli altri. La comunicazione avviene in questo caso tramite
l invio di messaggi su una qualche rete, la cui topologia varia a seconda dei casi.
Sono i pi facili da realizzare, ma richiedono opportune tecniche per ottenere un
elevato grado di parallelismo senza avere effetti negativi sulle prestazioni. Un
esempio di questo tipo di sistema in figura d.
CPU
RAM
CPU
RAM
Figura D. Esempio di sistema NORMA
3.2 I sistemi operativi multiprocessore
Un sistema operativo multiprocessore deve includere le funzionalit presenti in
quelli monoprocessore, adattandole ed estendendole a causa della maggiore
complessit dell hardware. Tutto ci senza degradare le prestazioni, essendo
proprio un miglioramento di queste l obiettivo che ci si pone con l utilizzo di
queste architetture. Dal punto di vista dell utente, desiderabile che il sistema
operativo renda il pi possibile trasparente la natura multiprocessore del sistema:
l utente non generalmente interessato a conoscere su quale CPU il suo processo
sar eseguito, ma solo che questo sia eseguito nel pi breve tempo possibile.
Questi sistemi operativi sono composti da kernel che girano su ciascun
processore, e che in qualche modo comunicano tra di loro. Il coordinamento tra i
vari kernel che si trovano su ogni CPU, pu avvenire o tramite un server unico al
quale giungono tutte le richieste che necessitano di una conoscenza dello stato
globale del sistema, oppure mediante l utilizzo di memoria condivisa il cui
accesso dai vari kernel avviene in mutua esclusione.
Indicheremo le funzionalit di base che un sistema operativo multiprocessore
deve fornire, avendo come riferimento quelle generalmente presenti in un sistema
- 16 -
operativo monoprocessore. Alcune delle problematiche esposte, in particolare
riguardo la sincronizzazione e la comunicazione tra i processi, saranno analizzate
anche riguardo alla realizzazione della comunicazione tra i vari kernel presenti nel
sistema.
3.2.1 Schedulazione
Supporremo che i processori presenti nel sistema siano equivalenti, nel senso
che ciascun processo possa essere eseguito indipendentemente su ciascuno di essi
(sistema omogeneo). Quando ci non si verifichi, poich ad esempio i vari
processi devono accedere ad hardware locale ai vari processori, o perch i tipi di
CPU siano addirittura diversi (sistema eterogeneo), il problema della
schedulazione si riconduce a quello di un sistema monoprocessore.
Nel caso di un sistema omogeneo, la determinazione dell algoritmo ottimale di
schedulazione dei processi sui vari processori presenta notevoli difficolt ,
maggiori di quelle che si avevano in un sistema monoprocessore in quanto in
questo caso si deve ottimizzare anche l utilizzo dei vari processori. Non si
possono enunciare risultati validi in ogni circostanza, dipendendo l algoritmo
ottimo dal tipo di applicazione che si considera. Ci limiteremo ad analizzare il
problema a grandi linee enunciando delle osservazioni valide in generale.
Un processo tradizionale (detto heavyweight) composto da un contesto
chiamato task formato da uno spazio indirizzi e altre informazioni, e da un
programma in esecuzione con le sue istruzioni, i suoi registri e generalmente il
suo stack, chiamato thread. Poich il cambio di contesto per passare da un task ad
un altro molto gravoso in termini di tempo richiesto, nella maggior parte dei
sistemi operativi possibile associare pi di un thread a ciascun task. Questa
possibilit ancora pi desiderabile in un sistema multiprocessore, poich
consente di esprimere un maggior parallelismo in un programma, e quindi di
suddividere l esecuzione del programma stesso tra i vari processori presenti.
In certi casi alcuni thread sono gestiti da delle librerie d utente e non dal
sistema stesso. Questa soluzione aumenta ulteriormente la flessibilit essendo tra
l altro il cambio di contesto tra questi thread ancora pi rapido, ma pu
peggiorare l utilizzo dei processori, in quanto ognuno di questi gruppi di thread
- 17 -
d utente viene schedulato dal sistema operativo come un unico thread, senza che
questo possa quindi effettuare nessun tipo di ottimizzazione.
Gli algoritmi di schedulazione per un sistema operativo monoprocessore
consistono generalmente nel mantenere una o pi code contenenti gli identificatori
dei thread in attesa di esecuzione, e nel prelevare di volta in volta quello da
avviare all esecuzione secondo una qualche politica. Questi algoritmi possono
essere facilmente adattati ad un sistema operativo multiprocessore mantenendo
queste code in aree di memoria globali, dalle quali ciascun kernel pu prelevare il
processo da avviare all esecuzione sul suo processore, oppure delegando la scelta
ad un server centrale. Possono essere presenti anche code locali per portare in
conto il fatto che alcuni processi possono essere eseguiti solo su alcuni processori,
dovendo ad esempio accedere a dell hardware collegato a questo.
Particolari ottimizzazioni vanno poi introdotte a seconda del tipo di sistema che
si considera. In un sistema NUMA o NORMA va per esempio evitata per quanto
possibile la migrazione dei processi tra i processori, poich questa determina lo
spostamento di codice e dati localmente al processore al quale stato spostato il
processo. Ø opportuno inoltre che anche nei sistemi UMA si cerchi per quanto
possibile di schedulare threads appartenenti allo stesso task di seguito sulla stessa
CPU, onde evitare cambi di contesto.
3.2.2 Gestione della memoria
Riguardo la gestione della memoria, nei sistemi UMA questa non si discosta di
molto da come avviene nel caso di un sistema monoprocessore. L unico fattore da
tenere in conto, che in questo tipo di sistemi l hardware realizza in genere un
certo grado di parallelismo nel suo accesso, che va sfruttato per quanto possibile.
Nei sistemi NUMA e NORMA la situazione invece pi complessa e porta,
generalmente nel caso dei NUMA, e per forza di cose nel caso dei NORMA, allo
spostare localmente i dati cui un processore accede durante l esecuzione di un suo
processo.
La necessit di accedere a dei dati che si trovano nella memoria di un altro
processore, pu verificarsi ad esempio in seguito allo spostamento dell esecuzione
di un processo da un processore ad un altro, oppure quando due processi che non
- 18 -
girano sullo stesso processore condividono alcuni dati. Ø compito dello
schedulatore il cercare d evitare queste situazioni, anche se in alcuni casi ci non
possibile. Alcune delle metodologie utilizzate per risolvere questo problema
sono:
• Migrazione. Con questo algoritmo i dati sono sempre spostati al processore
che ne richiede l accesso: questo tipo di algoritmo tanto pi efficiente
rispetto ad altri, quanti meno spostamenti sono richiesti.
• Replicazione in lettura. La richiesta di accesso in lettura a dei dati
localizzati su di un altro processore, comporta la creazione di una loro copia
locale, che pu essere eliminata quando non pi richiesta. La copia locale
cos creata accessibile solo in lettura e deve essere aggiornata ogni volta
che i dati originari vengono modificati. Questo algoritmo risulta efficiente
nel caso in cui la maggior parte degli accessi avvenga in lettura. Pu essere
inoltre abbinato ad un algoritmo di migrazione, che provvede a fare in modo
che il possesso dei dati sia spostato al processore che li modifica.
• Replicazione completa. Con questo algoritmo una stessa struttura dati pu
essere presente contemporaneamente su vari processori, disponibile sia in
lettura che in scrittura. Dovendo garantire la consistenza tra le varie copie
richiede la presenza di opportuni algoritmi per la sua implementazione,
simili a quelli che si utilizzano per la realizzazione della consistenza delle
cache nei processori.
Gli algoritmi introdotti si preoccupano solo di come gestire la condivisione dei
dati tra i vari processori; una volta che i dati siano disponibili nello spazio
indirizzabile dal processore che li richiede, un ulteriore problema che va
affrontato quello di conservare la coerenza degli indirizzi. Non detto infatti che
la stessa struttura dati venga posta allo stesso indirizzo sui vari processori, e ci
deve essere portato in conto in qualche modo, ad esempio correggendolo tramite
la Memory Management Unit (MMU) dei vari processori.
Un altro modo per evitare questo problema, e contemporaneamente ottimizzare
gli spostamenti dei dati tra i processori, si ha mediante l utilizzo della memoria
virtuale distribuita. Questa estende ad un sistema distribuito il concetto di
memoria virtuale, facendo in modo che tutti i processori condividano un unico
spazio indirizzi per la memoria. Nel momento in cui si accede ad una pagina i cui
- 19 -
dati non si trovano localmente al processore, una delle tecniche introdotte per lo
spostamento dei dati tra i processori viene utilizzata. Notiamo come in questo caso
non sia presente il problema della correzione dell indirizzamento, essendo lo
spazio indirizzi comune a tutti i processori, e inoltre come vengano spostate solo
le pagine di memoria cui un processore realmente accede. Anche questo approccio
presenta comunque dei problemi: i vari processori devono essere omogenei tra di
loro per quel che riguarda la gestione della memoria (ad esempio devono avere la
stessa dimensione per la pagine), e lo spazio indirizzabile pu diventare troppo
grande in alcuni casi, con i problemi di efficienza che ci comporta.
3.2.3 Sincronizzazione
La presenza di primitive di sincronizzazione tra processi che consentano la
mutua esclusione nella loro esecuzione, necessaria per proteggere le sezioni
critiche, e quindi la consistenza della memoria tra di loro condivisa, oltre che per
garantire una certa successione temporale nelle azioni realizzate.
In un sistema operativo multiprocessore possono essere implementate a livello
di sistema, tutte le primitive di sincronizzazione tra i processi normalmente
presenti anche nei sistemi operativi monoprocessore, quali ad esempio i semafori
e le variabili condition. Affronteremo quindi in particolare solo il problema della
sincronizzazione dei processi che si trovino su processori diversi: questa infatti
la situazione che si verifica quando i vari kernel che si trovano su processori
diversi devono modificare le strutture dati tra di loro condivise in sistemi UMA e
NUMA.
Un lock una struttura dati condivisa utilizzata per realizzare la mutua
esclusione tra i processi, in quanto ciascun lock pu essere posseduto da un solo
processo alla volta. Su di un lock possono essere realizzate due operazioni, che
chiameremo acquisisci_lock e rilascia_lock. La prima cerca di trasferire il possesso
del lock cui fa riferimento al processo che la chiama, ponendolo in qualche modo
in attesa se il lock in quel momento posseduto da un altro processo. La seconda
rilascia il possesso del lock cui fa riferimento, consentendo l avanzamento di uno
dei processi in attesa su di esso. Per realizzare una sezione critica, basta quindi
racchiuderla tra le due chiamate acquisisci_lock e rilascia_lock.
- 20 -
Uno dei modi per realizzare queste due chiamate prevede la presenza in
hardware di un istruzione Test-and-Set, che restituisce il valore di una locazione
di memoria e ve ne scrive uno nuovo con un operazione indivisibile: ci significa
che l operazione non interrompibile da cause interne al processore come l arrivo
di un interruzione, e che altri processori non possono accedere a quella locazione
finch l operazione non completata.
void acquisisci_lock(char *lock)
{
while (Test_and_Set(lock, 1));
}
void rilascia_lock(char *lock)
{
*lock = 0;
}
Figura E. Esempio di realizzazione delle primitive sui lock mediante l’utilizzo
dell’operazione Test-and-Set
Associando quindi ad esempio ad un lock il valore 1 se questo appartiene a
qualcuno e 0 se libero, un esempio in C di come realizzare le primitive richieste
in figura e. Notiamo come l operazione acquisisci_lock si traduce in una sorta di
attesa attiva se il lock non libero: la richiesta di acquisizione ripetuta finch
non viene soddisfatta. Ci presuppone ovviamente che il possesso del lock sia di
un processo che si trova su di un altro processore. Nel caso in cui ci non sia vero
sono possibili altre soluzioni che a prima vista sembrerebbero in ogni caso pi
efficienti, come ad esempio bloccare l esecuzione del processo in attesa sul lock,
schedulandone un altro finch questo non sia stato rilasciato. La soluzione
introdotta si dimostra essere per pi efficiente nel caso di contesa tra processi che
si trovano su processori diversi, quando le regioni critiche sono piccole, poich in
questo caso il numero di tentativi che si compiono non molto elevato, e si evita
la rischedulazione del processo in esecuzione che causerebbe una perdita di tempo
maggiore. Ø possibile eventualmente aggiungere delle piccole pause tra due
tentativi successivi, onde evitare che la contesa sul bus che gli accessi al lock
determina, causi un rallentamento nell esecuzione degli altri processi e quindi
- 21 -
eventualmente del rilascio del lock stesso. Notiamo infine come l algoritmo
introdotto non garantisca nessun ordine particolare per l ingresso di vari processi
nella sezione critica.
Equivalentemente all istruzione Test-and-Set, l hardware pu prevedere la
presenza di una istruzione Swap che scambi atomicamente il contenuto di due
locazioni di memoria.
Nel caso in cui sia possibile distinguere i processi in lettori e scrittori, sono
possibili altre ottimizzazioni a questo modello, consentendo ad esempio a vari
processi lettori di ottenere contemporaneamente il possesso di un lock, fintanto
che questo non appartenga a nessun processo scrittore.
Un altro modo per realizzare la sincronizzazione, tramite un evento. Questi
vengono utilizzati principalmente per garantire una certa successione temporale:
un processo blocca la sua esecuzione su di un evento finch questo non si verifica.
Il concetto di evento pu essere utilizzato per la sincronizzazione tra kernel che si
trovino su processori diversi in sistemi UMA e NUMA, collegati da un bus che
consenta la propagazione delle interruzioni. La routine di gestione delle
interruzioni di un certo kernel sar quindi in attesa sull evento interruzione
generato da un altro kernel, e al suo arrivo potr prendere le opportune decisioni.
3.2.4 Comunicazione tra i processi
Il problema della comunicazione tra i processi pu essere risolto da un sistema
operativo in due modi:
• modello di comunicazione a memoria comune: si utilizza una memoria
condivisa tra i processi che intendono comunicare tra di loro, allocata dal
sistema operativo tramite opportune chiamate, e una primitiva di
sincronizzazione per realizzare la mutua esclusione nell accesso;
• modello di comunicazione a scambio di messaggi: il sistema operativo
prevede delle primitive per realizzare l invio di messaggi tra i vari processi,
del tipo send e receive; il loro modo di funzionamento varia molto da
implementazione a implementazione, potendo essere sincrone o asincrone,
direttamente tra processi o tramite l utilizzo di porte, e cos via. Notiamo
come l invio di messaggi sincroni possa essere utilizzato anche per la