Operazione: Descrizione dell'architettura Run-time
Questa attività definisce l'architettura di un processo per il sistema in termini di classi attive e delle relative istanze e la loro relazione con i thread e processi del sistema operativo.
Scopo
  • Per analizzare i requisiti concorrenza,
  • Per identificare i processi e i relativi cicli di vita 
  • Per identificare i meccanismi di comunicazione interni al processo e allocare le risorse di coordinamento interne al processo
  • Per distribuire gli elementi modello tra i processi.
Relazioni
Descrizione principale

Gli oggetti attivi (cioè, le istanze delle classi attive) sono utilizzati per rappresentare i thread di esecuzione simultanei nel sistema: in modo teorico, ciascun oggetto attivo ha il proprio thread di controllo e, convenzionalmente, è la radice principale di un frame dello stack di esecuzione. L'associazione degli oggetti attivi agli effettivi thread o processi del sistema operativo può variare a seconda dei requisiti di risposta e sarà influenzata da valutazioni sull'eccesso dei passaggi di contesto. Ad esempio, è possibile per un numero di oggetti attivi, in combinazione con un semplice programma di pianificazione, condividere un singolo thread del sistema operativo, mostrando pertanto di avere un'esecuzione simultanea. Tuttavia, se uno qualsiasi degli oggetti attivi evidenzia sintomi di blocco, ad esempio eseguendo operazioni di input-output sincrone, gli altri oggetti attivi nel gruppo non saranno in grado di rispondere agli eventi che si verificheranno mentre il thread del sistema operativo è bloccato.

D'altro canto, fornendo a ciascun oggetto attivo il proprio thread di sistema operativo può determinare una più rapida risposta, a patto che le risorse di elaborazione non siano contrariamente influenzate dall'ulteriore eccesso di passaggi di contesto.

Nei sistemi in tempo reale, le capsule descritte nella sezione Prodotto di lavoro: Capsule sono il modo consigliato per modellare la simultaneità; come per le classi attive, ciascuna capsula ha il proprio thread di controllo notazionale, ma le capsule hanno ulteriori semantiche di composizione e di incapsulamento per rendere la modellazione di complessi problemi in tempo reale più trattabile.

Questa attività definisce l'architettura di un processo per il sistema in termini di classi attive e delle relative istanze e la loro relazione con i thread e processi del sistema operativo. Allo stesso modo, per sistemi in tempo reale, l'architettura del processo sarà definita in termini di capsule e di una mappatura associata di queste ai processi e thread del sistema operativo.

Nella fase iniziale di elaborazione, questa architettura sarà alquanto preliminare, ma nella fase finale i processi e thread dovrebbero essere ben definiti. I risultati di questa attività vengono catturati nel modello di progettazione - in particolare, nella vista processi (consultare la sezione Concetto: Vista processi).

Passi
Analisi dei requisiti di simultaneità
Scopo  Per definire l'ambito in cui è richiesta l'esecuzione parallela per il sistema. Questa definizione sarà di guida per strutturare l'architettura. 

Durante l'Task: Identificazione degli elementi di progettazione, sono stati considerati i requisiti di simultaneità gestiti principalmente dalle domande effettuate spontaneamente per la concorrenza nel dominio del problema. 

Il risultato conseguente è stato un'insieme di classi attive, che rappresentano i thread logici di controllo nel sistema.  Nei sistemi in tempo reale, queste classi attive sono rappresentate da Prodotto di lavoro: Capsula.

In questa fase, vengono considerate altre fonti dei requisiti di concorrenza - quelle previste dai requisiti non funzionali del sistema.

I requisiti di concorrenza sono gestiti da:

  • Il livello in cui deve essere distribuito il sistema. Un sistema il cui funzionamento deve essere distribuito su processori o nodi richiede virtualmente un'architettura a più processi. Un sistema che utilizza qualche tipo di sistema di gestione del database o gestore delle transazioni deve anche tenere conto dei processi che tali sottosistemi principali forniscono.
  • La rapidità di calcolo degli algoritmi chiave. Per poter fornire degli ottimi tempi di risposta, potrebbe essere necessario assegnare delle intense attività di calcolo ad un processo o thread in modo che il sistema possa essere ancora in grado di rispondere agli input dell'utente mentre viene eseguito il calcolo, sebbene con poche risorse.
  • Il livello di esecuzione parallela supportata dall'ambiente. Se il sistema operativo o ambiente non supporta i thread (processi leggeri), è di scarsa importanza considerarne il loro impatto sull'architettura del sistema.
  • La necessità della funzione di tolleranza dell'errore nel sistema. I processori di backup richiedono un processo di copia e la necessità di avere i processi primari e di backup sincronizzati.
  • Il modello di arrivo degli eventi nel sistema. In sistemi con unità esterne o sensori, i modelli di arrivo di eventi in entrata possono differire da sensore a sensore. Alcuni eventi possono essere periodici (ad esempio verificarsi durante un intervallo prefissato, con più o meno un tempo minimo) oppure aperiodici (ad esempio con un intervallo irregolare). Le classi attive che rappresentano le unità che generano diversi modelli di eventi saranno di solito assegnate a diversi thread del sistema operativo, con differenti algoritmi di pianificazione, per essere certi di non mancare gli eventi o le scadenze di elaborazione (nel caso questo sia un requisito del sistema). Tale ragionamento si applica in modo uguale alle capsule, quando utilizzate nella progettazione dei sistemi in tempo reale.

Così come per molti problemi strutturali, questi requisiti possono essere alquanto esclusivi in modo reciproco. E' probabile che si abbia, almeno inizialmente, dei requisiti in conflitto. La classificazione dei requisiti in termini di importanza faciliteranno l'utente nella risoluzione del conflitto.

Identificazione dei processi e thread
Scopo  Per definire i processi ed i thread che saranno presenti nel sistema. 

L'approccio più semplice è di allocare tutti gli oggetti attivi in un thread o processo comune e di utilizzare un semplice programma di pianificazione degli oggetti attivi, poiché ciò riduce l'eccesso di passaggio di contesto. Tuttavia, in alcuni casi, potrebbe essere necessario distribuire gli oggetti attivi su uno o più thread o processi. Ciò sarà quasi certamente il caso della maggior parte dei sistemi in tempo reale, dove le capsule utilizzate per rappresentare i thread logici in alcuni casi devono soddisfare rigidi requisiti di pianificazione.

Se un oggetto attivo che condivide un thread del sistema operativo con altri oggetti attivi esegue una chiamata sincrona ad un altro processo o thread e ciò blocca il thread del sistema operativo condiviso dell'oggetto che viene richiamato, tale operazione sospenderà automaticamente tutti gli altri oggetti attivi presenti nel processo richiamato. Ora, ciò non deve il caso in questione: una chiamata sincrona dal punto di vista dell'oggetto attivo potrebbe essere gestita in modo asincrona da parte del programma di pianificazione che controlla il gruppo di oggetti attivi - il programma di pianificazione sospende l'oggetto attivo che esegue la chiamata (attendendo la conclusione della chiamata sincrona) e quindi pianifica l'esecuzione di altri oggetti attivi. 

Quando l'operazione 'sincrona' originale viene completata, è possibile ripristinare l'oggetto attivo che viene richiamato. Tuttavia, questo approccio potrebbe non essere sempre possibile, poiché il programma di pianificazione potrebbe non essere realizzato per intercettare tutte le chiamate sincrone prima che vengano bloccate. Da notare che una chiamata sincrona tra oggetti attivi che utilizzano lo stesso processo o thread del sistema operativo può essere gestita, per generalità, in questo modo dal programma di pianificazione - ed è equivalente in realtà a una chiamata di procedura dal punto di vista dell'oggetto attivo che si sta richiamando.

Ciò conduce alla conclusione che gli oggetti attivi devono essere raggruppati in processi o thread in base alle rispettive esigenze di essere eseguiti simultaneamente con chiamate sincrone che bloccano il thread. Vale a dire, l'unica eccezione in cui un oggetto attivo deve essere integrato nello stesso processo o thread con un altro oggetto che utilizza chiamate sincrone che bloccano il thread è quando non ha necessità di essere processato simultaneamente con quell'oggetto e può tollerare di non essere eseguito mentre l'altro oggetto è bloccato. Nel caso estremo, quando la velocità di risposta è determinante, potrebbe risultare necessario un thread o processo separato per ogni oggetto attivo.

Nei sistemi in tempo reale, l'utilizzo di interfacce basate su messaggi delle capsule significa che è più facile elaborare un programma di pianificazione che garantisca, almeno per comunicazioni capsula a capsula, l'operatività ininterrotta dei thread del sistema operativo supportato, anche quando una capsula comunica in modo sincrono con un'altra capsula. Tuttavia, è ancora possibile per una capsula emettere una richiesta direttamente al sistema operativo, ad esempio, per un'attesa programmata sincrona, che bloccherebbe il thread. E' necessario stabilire delle convenzioni, per i servizi di livello inferiore richiamati dalle capsule, che evitano questo comportamento, nel caso le capsule debbano condividere un thread comune (e utilizzare un semplice programma di pianificazione per simulare la simultaneità).

Come regola generale, nelle situazioni sopra riportate è preferibile utilizzare processi leggeri anziché processi complessi poiché determinano un minore sovraccarico. Tuttavia, resta l'obbiettivo di sfruttare alcune delle speciali caratteristiche dei processi in determinati casi essenziali. Poiché i thread condividono la stessa area di indirizzamento, essi sono inerentemente più rischiosi dei processi. Se la possibilità di una sovrascrittura accidentale non è tollerabile, è preferibile utilizzare i processi. Inoltre, poiché i processi rappresentano unità indipendenti di ripristino nella maggior parte dei sistemi operativi, potrebbe essere utile assegnare gli oggetti attivi ai processi in base alle rispettive necessità di essere ripristinati in modo indipendente. In conclusione, tutti gli oggetti attivi che devono essere ripristinati come un'unità possono essere integrati insieme nello stesso processo.

Per ciascun flusso separato del controllo richiesto dal sistema, creare un processo o thread (processo lightweight). Si consiglia l'utilizzo di un thread nei casi in cui è richiesto un flusso del controllo nidificato (ad esempio, se all'interno di un processo occorre un flusso indipendente del controllo a livello di attività secondaria).

Ad esempio, si potrebbero utilizzare thread separati del controllo per:

  • Suddividere le problematiche tra diverse aree del software
  • Sfruttare più CPU in un nodo o in più nodi di un sistema distribuito
  • Aumentare l'utilizzo della CPU mediante allocazione dei cicli ad altre attività quando viene sospeso un thread del controllo
  • Dare una priorità alle attività
  • Supportare la condivisione del carico su diversi processi e processori
  • Raggiungere una più elevata disponibilità del sistema mediante processi di backup
  • Supportare il DBMS, il Transaction Manager o altri principali sottosistemi.

Esempio

Nello sportello automatico ATM (Automated Teller Machine) gli eventi asincroni devono essere gestiti da tre diversi sorgenti: l'utente del sistema, i dispositivi ATM (nel caso di un blocco del distributore banconote, ad esempio) o la rete ATM (nel caso di una direttiva di chiusura dalla rete). Per gestire questi eventi asincroni, è possibile definire tre diversi thread di esecuzione all'interno dell'ATM stesso, come mostrato di seguito utilizzando le classi attive in UML.

Illustrazione di processi e thread dello sportello automatico ATM

Processi e thread all'interno dell'ATM

Identificazione dei cicli di vita del processo
Scopo  Per identificare quando i processi e i thread vengono creati ed eliminati. 

Ciascun processo o thread del controllo deve essere creato ed eliminato. In un'architettura a processo singolo, la creazione del processo si verifica quando l'applicazione viene avviata e l'eliminazione del processo quando l'applicazione viene terminata. Nelle architetture a più processi, i nuovi processi (o thread) vengono tipicamente generati o duplicati dal processo iniziale creato dal sistema operativo quando l'applicazione viene avviata. Anche tali processi devono essere eliminati in modo esplicito.

La sequenza degli eventi che porta alla creazione ed eliminazione del processo deve essere determinata e documentata, così come il meccanismo per la creazione ed eliminazione.

Esempio

Nello sportello automatico ATM (Automated Teller Machine), viene avviato un processo principale che è responsabile per il coordinamento della funzionalità dell'intero sistema. Tale processo produce un numero di thread di controllo subordinati per controllare le diverse parti del sistema: le unità nel sistema e gli eventi provenienti dal cliente e dalla rete ATM. La creazione di questi processi e thread può essere mostrata con classi attive in UML e la creazione delle istanze di tali classi attive può essere mostrata in un diagramma di sequenza, come riportato di seguito:

Illustrazione della creazione del processo e thread di avvio del sistema

Creazione dei processi e thread durante l'inizializzazione del sistema

Identificazione dei meccanismi di comunicazione dei processi interni
Scopo  Per identificare le modalità di comunicazione dei processi e thread. 

I meccanismi IPC (Inter-process communication) abilitano l'invio dei messaggi tra gli oggetti che vengono eseguiti in processi separati.

I meccanismi tipici di comunicazione dei processi interni includono:

  • Memoria condivisa, con o senza semafori per garantire la sincronizzazione.
  • Rendezvous, soprattutto quando supportato direttamente da un linguaggio come Ada
  • Semafori, utilizzati per bloccare l'accesso simultaneo alle risorse condivise
  • Passaggio di messaggi, sia punto a punto che punto a più punti
  • Caselle postali
  • RPC - Chiamate di procedure remote
  • Trasmissione di eventi - utilizzando un "bus software" ("architettura del bus di messaggi")

La scelta del meccanismo IPC cambierà il modo in cui verrà modellato il sistema; in "un'architettura bus del messaggio", ad esempio, non sono richieste associazioni esplicite tra oggetti per inviare i messaggi.

Allocazione delle risorse di coordinamento dei processi interni
Scopo Per allocare scarse risorse
Per anticipare e gestire potenziali colli di bottiglia delle prestazioni 

Sono solitamente rari i meccanismi di comunicazione dei processi interni. I semafori, la memoria condivisa e le caselle postali sono solitamente prefissati in dimensione o numero e non possono essere incrementati senza un costo significativo. L'RPC, i messaggi e le trasmissioni di eventi richiedono in modo crescente una larghezza di banda rete scarsa. Quando il sistema supera la soglia di una risorsa, subisce di solito un calo non lineare delle prestazioni: una volta consumata una risorsa scarsa, le successive richieste della risorsa avranno probabilmente un esito non desiderato.

Se non sono disponibili le risorse scarse, occorre considerare diverse strategie:

  • ridurre la necessità delle risorse scarse mediante riduzione del numero di processi
  • cambiare l'utilizzo delle risorse scarse (per uno o più processi, scegliere una diversa e meno scarsa risorsa da utilizzare per il meccanismo IPC)
  • aumentare la quantità delle risorse scarse (ad esempio, aumentando il numero di semafori). Ciò può essere effettuato relativamente per piccole modifiche, ma spesso determina degli effetti collaterali o presenta dei limiti prefissati.
  • condividere le risorse scarse (ad esempio, allocando la risorsa solo quando è richiesta e rilasciandola appena terminato). Quest'operazione è costosa e può solo prevenire la mancanza di risorse.

Indipendentemente dalla strategia scelta, le attività del sistema dovrebbero degradare lentamente (anziché subire un'interruzione) e fornire un feedback sufficiente all'amministratore di sistema per consentire la risoluzione del problema (se possibile) nel campo una volta distribuito il sistema.

Se il sistema richiede una particolare configurazione dell'ambiente di runtime per poter aumentare la disponibilità di una risorsa critica (controllo frequente mediante riconfigurazione del kernel del sistema operativo), occorre che l'installazione del sistema venga eseguita automaticamente oppure che il responsabile del sistema svolga queste operazioni prima che il sistema diventi operativo. Ad esempio, potrebbe essere necessario riavviare il sistema prima di rendere effettiva la modifica.

Associazione dei processi all'ambiente di implementazione
Scopo  Per associare i "flussi di controllo" ai concetti supportati dall'ambiente di implementazione. 

I processi concettuali devono essere associati a specifiche costruzioni nell'ambiente operativo. In moti ambienti esistono diversi tipi di processi, molto spesso processi e thread. Le scelte saranno effettuate in base al livello di dipendenza (i processi sono autonomi, mentre i thread vengono eseguiti nel contesto di un processo racchiuso) e ai requisiti delle prestazioni del sistema (la comunicazione interna del processo tra i thread è solitamente più veloce e più efficiente rispetto a quella tra i processi).

In molti sistemi, potrebbe essere presente un numero massimo di thread per processo o di processi per nodo. Questi limiti non sono assoluti, ma possono limiti pratici imposti dalla disponibilità delle risorse scarse. I thread e processi già in esecuzione su un nodo di destinazione devono essere presi in considerazione insieme ai thread e processi presentati nell'architettura del processo. Occorre tenere in considerazione i risultati della fase precedente, Allocazione delle risorse di coordinamento interne del processo, quando la mappatura viene eseguita per garantire che non venga creato un nuovo problema sulle prestazioni.

Associazione degli elementi di progettazione ai thread di controllo
Scopo  Per determinare quali thread delle classi di controllo e dei sottosistemi devono essere eseguiti. 

Le istanze di un dato sottosistema o classe devono essere eseguite all'interno di almeno un thread di controllo che fornisce l'ambiente di esecuzione per la classe o il sottosistema; di fatto possono essere eseguite in numerosi processi differenti.

Con l'utilizzo di due diverse strategie simultaneamente, è possibile determinare la "giusta" quantità di concorrenza e definire la "corretta" serie di processi:

Inside-out (dall'interno verso l'esterno)

  1. A partire del modello di progettazione, le classi di gruppo ed i sottosistemi uniti in delle serie di elementi di cooperazione che (a) collaborano tra loro strettamente e (b) devono essere eseguite nello stesso thread di controllo. Prendere in considerazione l'impatto che ne consegue l'introduzione della comunicazione interna del processo all'interno di una sequenza di messaggi prima di suddividere gli elementi in thread di controllo separati.
  2. Contrariamente, separare le classi ed i sottosistemi che non interagiscono, collocandoli in diversi thread di controllo.
  3. Questa operazione di raccolta in un cluster procede finché il numero di processi non è stato ridotto al minimo possibile che comunque consente la distribuzione e l'uso delle risorse fisiche.

Outside-in (dall'esterno verso l'interno)

  1. Identificare le emissioni esterne a cui il sistema deve rispondere. Definire un thread di controllo separato per gestire ciascuna emissione e un thread di controllo separato per fornire ciascun servizio.
  2. Utilizzare l'integrità dei dati e i vincoli di serializzazione per ridurre questa serie iniziale di thread di controllo al numero supportato dall'ambiente di esecuzione.

Non esiste un processo deterministico e lineare che conduce a una vista processi ottimale; sono richieste poche iterazioni per raggiungere un compromesso accettabile.

Esempio

Il seguente diagramma illustra in che modo le classi all'interno dell'ATM vengono distribuite tra i processi ed i thread nel sistema.

Illustrazione della distribuzione della classe ATM tra processi e thread

Mappatura delle classi con i processi per lo sportello automatico ATM



Proprietà
Ricorrenze multiple
Attivato da evento
In corso
Facoltativo
Pianificato
Ripetibile
Ulteriori informazioni