- userLoginStatus
Welcome
Our website is made possible by displaying online advertisements to our visitors.
Please disable your ad blocker to continue.
Architettura degli elaborati e sistemi operativi - informatica
Raccolta domande esame - Parte teorica
Other
1.Il Data path della macchina di Von Neumann è composto da dei registri, solitamente da 1 a 32, una ALU (Unità aritmetico-logica), due registri di input dell’ALU, un registro di output e dei bus che collegano le diverse parti tra di loro. La ALU esegue semplici operazioni sugli input e genera un output memorizzato in un apposito registro. Questo valore può successivamente essere immagazzinato in un registro della CPU per essere riutilizzato in seguito. La ALU, inoltre, oltre a semplici operazioni come somma o sottrazione è in grado di eseguire istruzioni di tipo: registro-memoria e registro-registro. Quelle registro-memoria consistono nel prelevamento di parole dalla memoria per spostarle nei registri. Quelle registro-registro consistono in operazioni fatte su operandi contenuti nei registri e la loro successiva memorizzazione. 2.L’esecuzione di una istruzione avviene tramite dei semplici passi in successione. Il cosìdetto ciclo esecutivo delle istruzioni, o ciclo di fetch-decode-execute, consiste in 7 operazioni: 1.Prelevamento della successiva istruzione dalla memoria per portarla nell IR; 2.Modifica del PC per farlo puntare all’istruzione seguente; 3.Determinazione del tipo di istruzione appena prelevata; 4.Se l'istruzione usa una parola in memoria, determinare dove si trova; 5.Se necessario, prelevare la parola per portarla in un registro della CPU; 6.Esecuzione dell’istruzione; 7.Tornare al punto 1 per iniziare l'esecuzione dell'istruzione successiva. L’interprete è un programma in grado di portare a termine un altro programma, prelevando, decodificando ed eseguendo le sue istruzioni. Esso viene utilizzato per scomporre le istruzioni in piccoli passi, rendendone più facile l’esecuzione da parte dell’hardware. 3.Per il miglioramento delle prestazione delle macchine, i progettisti di calcolatori hanno trovato nel parallelismo la migliore soluzione. Per parallelismo si intende la capacità di eseguire più azioni nello stesso istante, esso può essere di due tipi: a livello di istruzione e a livello di processore. Mentre quello di processore consiste nel far lavorare più CPU parallelamente, quello di istruzione consiste nel pipelining. Le architetture con pipeline hanno come concetto di base la suddivisione delle istruzioni in più fasi che possono essere eseguite in parallelo, da componenti hardware dedicati. Una CPU con pipeline è composta da cinque stadi specializzati (1)Unità di fetch dell'istruzione; 2)Unità di decodifica dell'istruzione; 3) Unità di fetch degli operandi; 4) Unità di esecuzione dell'istruzione; 5) Unità di memorizzazione del risultato), ad ogni stadio provvede a svolgere in maniera sequenziale un solo compito specifico per l'elaborazione di una certa istruzione; ad ogni ciclo di clock dall'ultimo stadio esce un'istruzione completata. Nello stesso istante ogni unità sta però elaborando in parallelo i diversi stadi di successive altre istruzioni. L’uso della pipeline permette di bilanciare la latenza e la larghezza di banda di un processore. 4.I codici di rilevazione e/o correzione degli errori sono codici che consentono la rilevazione e/o la correzione degli errori in una parola. L’algoritmo sul quale si basano i codici a correzione di errori è quello della distanza di Hamming: Tra due parole di codice vi è una distanza di Hamming pari a “d”, allora saranno necesserari ”d” errori singoli per trasformare una parola nell'altra. Si definisce distanza di Hamming di un codice la minima distanza tra due parole di un codice. Per rilevare “d” errori singoli è necessario un codice con distanza di Hamming “d+1”, mentre per correggere “d” errori singoli è necessario un codice con distanza di Hamming “2d+1”. Nei codici di rilevazione e/o correzione di errori si utilizzano alcuni bit extra (ridondanti) che vengono aggiunti alla parola stessa, i cosiddetti “bit di parità”. Questa semplice tecnica è utilizzata nel codice di Hamming. Essa consiste nell’aggiunta, in base alla grandezza originaria della parola, di n bit di parità. Questi bit vengono aggiunti nella posizione 1 e nelle posizioni corrispondenti alle potenze di 2 ed ognuno di loro controlla alcuni bit. Ciascun bit di parità controlla i bit presenti in posizioni specifiche ed è impostato in modo che sia pari il numero totali di bit che hanno valore 1 nelle posizioni corrette. Grazie a questo codice è possibile trovare e correggere errori singoli all’interno della parola di codice. 5.La memoria cache è una memoria di piccole dimensioni ma dalla velocità molto elevata. Quando la CPU necessita di una parola, la cerca nella cache e solo nel caso in cui non la trova accede nella memoria centrale. Soltanto le parole usate più frequentemente sono mantenuto all'interno della cache. Le informazioni salvate in una memoria cache seguono questi principi : -principio di località spaziale: riflette la considerazione che è molto probabile che in un porissimo futuro si possa accedere a locazioni di memoria i cui indirizzi sono numericamente simili a quello di una locazione appena utilizzata; -principio di località temporale: si verifica quando si accede nuovamente a locazioni di memoria già utilizzate di recente. Per sfruttare il principio di località, le memorie sono organizzare in linee di cache. Per i progettisti vi sono 5 principali problemi nella progettazione di un elaboratore dotato di memorie cache: la grandezza della cache, la dimensione della linea di cache, l’organizzazione delle parole all’interno delle linee, l’utilizzo di una cache unificata o la suddivisione in più cache e l’eventuale numero di cache. Attualmente è comune avere chip contenenti una cache primaria, avere una cache secondaria esterna al chip ma interna al circuito della CPU e una terza cache più distante. Una tecnica elementare che funziona in modo efficace consiste nell'introdurre due cache separate: una per le istruzioni e una per i dati (cache separata), in modo da far partire operazioni di memoria indipendentemente per ciascuna cache. Spesso tra la memoria centrale e la cache delle istruzioni e dei dati è presente un'altra cache, chiamata cache di secondo livello. Per disporre di sistemi di memoria ancora più sofisticati si possono avere anche tre o più livelli di cache. •Cache a corrispondenza diretta: Ciascun elemento della cache può memorizzare esattamente una linea di cache della memoria centrale. Gli elementi della cache sono composti da tre parti: ◦bit valid: indica se il dato nell'elemento è valido o no ◦campo tag: valore univoco a 16 bit, corrispondente alla linea di memoria da cui provengono i dati ◦campo data: contiene una copia del dato della memoria. Per prelevare e memorizzare dati dalla cache l'indirizzo è suddiviso in 4 campi: •bit valid: corrisponde ai bit tag memorizzati in un elemento della cache. •Campo line: indica l'elemento della cache contenente i dati corrispondi, se presenti. •Campo word: indicia a quale parola si fa riferimento all'interno della linea •campo byte: generalmente non utilizzato, ma se si richiede un solo byte esso indica quale byte è richiesto all'interno della parola cache hit: se il campo tag dell'elemento della cache e il campo tag dell'indirizzo di memoria corrispondono. Cache miss: se l'elemento della cache non è valido o se i campi tag non corrispondono. •Cache set associative: è una cache con n possibili elementi per ciascun indirizzo. E' necessario controllare un insieme di n elementi per vedere se la linea richiesta è presente nella cache. Algoritmo utilizzato: LRU => mantiene un ordinamento temporale di ciascun insieme di elementi ai quali si può far riferimento in base ad una certa locazione di memoria. Quando si accede ad una delle linee presenti nella cache l'algoritmo aggiorna la lista marcando l'elemento utilizzato più recente. Quando giunge il momento di sostituire un elemento, l'algoritmo scarta quello che si trova alla fine della lista, cioè quello al quale è stato effettuato un accesso meno di recente. L'aggiornamento immediato nella memoria centrale dell'elemento della cache è chiamato write through: un metodo semplice e affidabile che richiede molto traffico verso la memoria. Write deferred: implementazione più sofisticata del precedente write allocation: quando i progetti ritardano la scrittura in memoria tendono a portare i dati all'interno della cache in caso di fallimento in scrittura. 6.L’organizzazione gerarchica delle memorie si basa principalmente su dimensione e velocità delle stesse. In cima alla gerachia vi sono i registri della CPU ai quasi di può accedere alla stessa velocità del processore stesso. Più sotto vi è la memoria cache che è più lenta dei registri ma ha dimensioni che variano da circa 32KB a qualche MB. Quella successiva è la memoria centrale con dimensioni che variano in base alla fascia delle macchine (tra 1 e centinaia di GB). Successivamente vi sono i dischi magnetici ed infine i dischi ottici ed i nastri magnetici. Come si può notare muovendosi verso il basso i due parametri sopracitati (dimensione e velocità) sono inversamente proporzionali, infatti la capacità aumenta ma la velcità di accesso diminuisce. 7.I dischi RAID (Redundant Array of Inexpensive/Indipendent Disks) si basano sull’idea di migliorare prestazioni ed affidabilità di un sitema di memorizzaqzione di massa utilizzando una batteria di dischi piuttosto che un unico disco. Al SO un disco RAID appare come un unico disco mentre, in realtà, si tratta di distribuzione parallela dei dati su più dischi. I RAID hanno la prorpietà di distribuire i dati sulle diverse unità consentendo elaborazioni parallele: Attualmente vi sono 6 livelli di RAID: RAID 0: Tecnica di striping: il disco RAID è visto come se ognugno dei suoi k setttori fosse diviso in strip (strisce). Vantaggio: lavora meglio quando le richieste sono di grandi dimensioni Svantaggio: non è ridondante RAID 1: In questo caso si usano due tecniche, striping e mirroring. Esso è un vero e proprio RAID in quanto duplica tutti i dischi creando dei backup. Vantaggi: - Una richiesta di lettura può essere eseguita dal disco più scarico - Una richiesta di scrittura deve essere eseguita su due dischi. - Il malfunzionamento di un disco è facilmente recuperabile Svantaggio: costo elevato RAID 2: Questo livello, a differenza dei precedenti, non opera su strip ma sulla base di una parola, un byte o un mezzo byte. Vantaggi: Lettura/scrittura in parallelo Svantaggi: dispendioso, molto lavoro al controllore, rotazione sincronizzata dei dischi RAID 3: Il livello 3 è la versione semplificata del 2, opera sempre sulla base di parole o byte, memorizza in parallelo singoli bit sui dischi, ma utilizza un solo disco per i bit di parità. Vantaggi: Lettura/scrittura in parallelo Svantaggi: rotazione sincronizzata dei dischi RAID 4: utilizza una parità strip-per-strip scritta su un disco aggiuntivo Vantaggi: Protegge dalla rottura di un disco Svantaggi: - prestazioni scarse se si cambiano piccole dimensioni di dati - Il disco per la parità diventa un problema per il sistema RAID 5: Il livello 5 è molto simile al 4 ma distribuisce in modalità round-robin i vari bit di parità tra tutti i dischi. Vantaggi: Protegge dalla rottura di un disco Svantaggi: - prestazioni scarse se si cambiano piccole dimensioni di dati 8.Nell’algebra di Boole variabili e funzioni possono assumere solo i valori di 0 e 1. Le operazioni fondamentali sono AND, OR e NOT. Le principali identità dell’algebra booleana sono: Inoltre le identità sono duali, ovvero di può creare una delle due forme a partire dall’altra scambiando AND con OR e anche 1 con 0. 9.I principi di De Morgan suggeriscono una notazione alternativa rispetto a quella standard, infatti, tramite questa legge si può dimostrare che una porta logica OR con gli input invertiti è equivalente a una porta NAND e una porta NOR può essere disegnata come una porta AND con gli input invertiti. Negando la legge, inoltre, si possono ottenere due rappresentazioni equivalenti delle porte logiche AND e OR. La tavola di verità della legge: 10.In logica digitale un multiplexer è un circuito con 2n dati in input, un valore di output e n input di controllo. Gli input di controllo gli permettono di selezionare uno degli input, che viene instradato verso l’output 11.In logica digitale un decodificatore è un circuito che accetta come input un numero a n bit e lo utilizza per impostare a 1 una sola delle 2n linee di output. 12.Un altro cicuito molto utile è il comparatore, che permette di confrontare due stringhe di bit. Esso accetta 2 input, ciascuno lungo 4 bit, e genera 1 se sono uguali o 0 se sono diversi. Questo circuito è basato sulla porta logica XOR (OR ESCLUSIVO) . 13.Una parte essenziale di qualsiasi CPU è un circuito che sia in grado di eseguire le somme. Esistono due diversi circuiti in grado di adempiere a questa necessità: half adder e full adder. L’half adder (o semisommatore) è in grado di sommare i bit meno significativi di due stringhe binarie calcolando il bit della somma e il bit del riporto. Tuttavia non è in grado di eseguire correttamente la somma con gli altri bit, dato che non riesce a gestire il riporto che arriva dalle posizioni precedenti. Per ovviare a questo problema è necessario un full adder (o sommatore) .Il loro funzionamento è abbastanza semplice, infatti i due dati di input vengono sommati tramite una porta logica XOR e si calcola il riporto con una porta AND. Nel sommatore il risultato in uscita dal primo half adder viene sommato al riporto in ingresso ottenendo la somma finale ed il riporto ottenuto tramite la porta AND si somma tramite una porta OR al riporto del primo half adder. 14.Per creare una memoria a 1 bit è necessario disporre di un circuito che “ricordi” i precedenti valori di input. Ci sono 2 tipi di circuiti in grado di adempiere a questa necessità: Latch e Flip-Flop. Il circuito Latch può essere di 3 tipi: Latch SR: si basa sui due input S (Setting) ed R (Resetting) e sui due output Q e Q complementari tra loro. Latch SR temporizzato: molto simile al precedente con l’aggiunta di un input, il clock, il cui valore è generalmente 0 e l’aggiunta di due porte AND che permettono al Latch di cambiare stato solo ed esclusivamente in specifici momenti, ovvero quando il clock assume un valore differente. Latch D temporizzato: per risolvere le ambiguità del Latch SR è stato ideato il Latch D nel quale è impossibile che si verifichi la situazione S=R=1, infatti vengono sostituiti i due input con D e con D. •Nel circuito Flip-Flop rispetto al Latch il momento in cui cambia lo stato non è quando il clock vale 1, bensì durante la transizione del clock da 0 a 1 (fronte di salita) oppure da 1 a 0 (fronte di discesa). A livello di circuito l’unica aggiunta è una porta AND sul clock e sul clock negato. 15.Un bus è un collegamento elettrico che unisce diversi dispositivi. I bus possono essere classificati in base alla loro funzione; alcuni di loro sono impiegati internamente alla CPU per trasferire dati da e verso la ALU, mentre gli altri sono esterni alla CPU e servono a connetterla con la memoria o con altri dispositivi di I/O. Il bus si basa sul ruolo attivo o passivo delle periferiche connesse, infatti quelle attive possono iniziare un trasferimento dati (master) mentre quelle passive restano in attesa di una richiesta (slave). Per la progettazione di un bus bisogna tenere conto di 4 punti fondamentali: Ampiezza del bus: per migliorare l’ampiezza si possono seguire tre strategie: aumentare il numero si linee con conseguente valutazione dei prezzi, aumentare la velocità di trasferimento con conseguente rischio di disallineamento del bus oppure l’utilizzo di bus multiplexati. Temporizzazione del bus: esistono due tipi di bus: sincroni e asincroni. Mentre i primi seguono il clock di sistema, i secondi non hanno un clock centralizzato e quindi i cicli di trasferimento non devono essere necessariamente uguali nella comunicazione tra dispositivi( Full Handshake -MSYN asserito -SSYN asserito in risposta a MSYN -MSYN negato in risposta a SSYN -SSYN negato in risposta a SSYN) Arbitraggio: può essere centralizzato o decentralizzato. In quello centralizzato vi è un arbitro che a fronte di richieste in input concede il bus alle periferiche richiedenti tramite uno schema daisy chain secondo in quale il dispositivo più vicino all’arbitro ottiene il controllo. In quello decentralizzato non vi è un arbitro, con conseguente abbassamento del prezzo, ma è presente una terza linea chiamata BUSY che permette ai dispositivi richiedenti di controllare se il bus è già utilizzato e, se libero, richiederlo. Operazioni del bus: capacità di lettura-scrittura di blocchi dati, operazioni di leggi-modifica-scrivi per l’accesso di più CPU al bus e gestione degli interrupt tramite controllore. 16.Introdotto nel 2008 come CPU a 4 processori, l’Intel Core i7 è il diretto discendente del 8088. L’architettura iniziale delle prime versioni era la “Nahalem”, mentre le versioni successive si basano sulla moderna architettura “Sandy Bridge”. Attualmente la CPU è venduta con un numero variabile di core (da 2 a 6) e ogni core è “hyperthreaded”, ovvero sono in grado di gestire più thread hardware attivi. Il Core i7 ha 3 livelli di cache. Ogni processore ha una cache dati di livello 1 da 32 KB, una cache istruzioni di livello 1 da 32 KB e una cache di livello 2 da 256 KB. Tutti i core, inoltre, condividono una cache unificata di livello 3 la cui dimensione varia dai 4 ai 15 MB. Nei sistemi Core i7 si utilizzano due principali bus esterni, entrambi sincroni: un bus di memoria DDR3 per l’accesso alla memoria centrale e un bus PCI Express per connettere il processore ai dispositivi di I/O. Questa CPU è realizzata in un supporto LGA e contiene 1115 pin. Disposizione logica contatti: -1155 pad -DDR1 e DDR2 bidirezionali per DRAM, clock a 666MHz -PCI Express: interfaccia seriale x16 linee -DMI: collegamento CPU-chipset -APIC(Advanced Programmable Interrupt Controller) Per ottimizzare gli accessi alla memoria il bus di memoria DDR3 del Corei7 è strutturato in pipeline in modo tale da porter supportare fino a 4 transazioni contemporaneamente; per poter fare questo la DRAM DDR3 è formata da 8 banchi di memoria e la sua interfaccia consente fino a 4 accessi concorrenti. Le richieste di memoria sono composte da 3 fasi: ←Fase di activate della memoria che apre una riga della DRAM per prepararla a successivi accessi ←Fasi di Read/Write in cui si possono effettuare accessi multipli a singole parole appartententi alla riga correttamente aperta della DRAM, oppure accessi multipli a una sequenza di parole appartententi alla riga corrente della DRAM con l'utilizzo del burst mode. ←Fase di PRECHARGE che chiude la riga corrente della DRAM e prepara la memoria per il prossimo comando ACTIVATE. 17.Il Data Path (o percorso dati) è quella parte della CPU che contiene la ALU, i suoi input e i suoi output. Solitamente questo è composto da dei registri a 32 bit che memorizzano il valore di alcune variabili del livello ISA o dati in I/O alla/dalla memoria centrale, la ALU, uno “shifter” che si occupa dello shift logico o aritmetico sull’output della ALU e dei bus che collegano le varie parti tra di loro. La maggior parte dei registri può inviare il proprio contenuto sul bus B, collegato in input alla ALU. L’output di quest’ultima guida lo shifter che a sua volta invia il proprio risultato sul bus C che scrive i valori su uno o più registri. 18.La microarchitettura Mic-1 è formata essenzialmente da due parti: il percorso dati e la sezione di controllo. L’elemento più importante della sezione di controllo è una memoria chiamata memoria di controllo. Essa è semplicemente un circuito che memorizza le microistruzioni invece delle istruzioni ISA. A differenza delle istruzioni, le microistruzioni richiedono maggiore flessibilità e quindi, ognuna di esse specifica in modo esplicito il proprio successore. Anche la memoria di controllo necessita di un proprio registro di indirizzo e di un proprio registro dei dati, infatti vi sono il MicroProgram Counter (MPC) e il MicroInstruction Register (MIR). Il funzionamento è il seguente: all’inizio di un ciclo di clock la parola contenuta nella memoria di controllo e puntata da MPC viene trasferita in MIR. Subito dopo, i vari segnali si propagano all’interno del percorso dati, grazie ad essi il contenuto di un registro viene inserito nel bus B e la ALU sa quale operazione eseguire. Dopo un intervallo l’output della ALU viene immagazzinato nello shifter e successivamente l’output finale raggiunge i registri tramite il bus C. Infine viene caricato MPC per puntare alla successiva microistruzione. 19.Un’istruzione consiste in un opcode (codice operativo), di solito corredato da altre informazioni quali la provenienza degli operandi e la destinazione dei risultati. Ogni istruzione, oltre all’opcode, può contenere nessuno, uno, due o tre indirizzi. Alcune macchina hanno tutte le istruzioni della stessa lunghezza, altre di lunghezza diversa. Per la progettazione di un buon ISA i progettisti devono tenere conto di diversi aspetti riguardanti le istruzioni: La lunghezza: a parità di progetto sono sempre preferibili quelle più corte, in quanto occupa meno spazio in memoria; Prevedere nel formato delle istruzioni spazio sufficiente a esprimere tutte le operazioni volute; Il numero di bit in un campo di indirizzi: Per una maggiore risoluzione nell’accesso alla memoria si paga al prezzo di indirizzi più lunghi e conseguentemente istruzioni più lunghe. 20.All’interno di un computer, i dati devono essere rappresentati in una forma specifica. A livello ISA sono disponibili una varietà di tipi di dati diversi. I tipi di dati possono essere essenzialmente suddivisi in due categorie: numerici e non. Ci sono interi di lunghezze diverse, in genere 8,16,32 e 64 bit. Per rappresentare tutti i numeri che non possono essere espressi con gli interi si usano i numeri in virgola mobile, questi sono lungi 32,64 o a volte 128 bit. Negli ultimi anni gli elaboratori sono diventati sempre più complessi per stare al passo con i servizi offerti dalle applicazioni non numeriche. I caratteri sono un tipo di dato importante in questo contesto, ma non tutti i computer ne forniscono il supporto hardware. I codici caratteri più comuni sono ASCII e UNICODE, che definiscono rispettivamente caratteri di 7 e 16 bit. Non è raro, inoltre, che il livello ISA sia dotato di supporto per la gestione delle stringhe. Anche i valori booleani sono importanti. Un valore booleano può assumero solo 2 valori 0 o 1, tuttavia viene utilizzata la convenzione che lo 0 è falso e tutto ciò che è diverso da 0 è vero. Un altro tipo di dato è il puntatore, ovvero un indirizzo di macchina. 21.E’ possibile classificare le operazioni nei seguenti tipi: Trasferimento dati: poter copiare dati da una locazione all’altra è fondamentale per tutte le operazioni. Ci sono due ragioni per trasferire dati: l’assegnamento di valori a variabili e prepararli a un accesso e un uso efficienti. Vi sono essenzialmente 4 tipi diversi di trasferimenti possibili: dalla memoria ai registri (LOAD), dai registri alla memoria (STORE), tra registri (MOVE) e copia tra locazioni di memoria. Operazioni binarie: sono quelle operazioni che producono un risultato dalla combinazione di due operandi. Queste si dividono in aritmetiche e booleane. Quelle aritmetiche sono le classiche operazioni di somma, sottrazione, moltiplicazione e divisione. Quelle booleane sono AND, OR e NOT e qualche volta XOR,NOR e NAND. Operazioni unarie: solo operazioni che prendono in ingresso un operando e restituiscono un risultato. Principalmente sono le istruzioni per lo scorrimento o la rotazione del contenuto di una parola. Confronti: sono operazioni che permettono di controntare tra loro numeri, parole o caratteri. Invocazione di procedura: consiste nella possibilità di richiamare in qualsiasi momento una procedura (un insieme di istruzioni che svolge un certo compito), conosciuta anche come subroutine o funzione. Istruzioni di ciclo: sono istruzioni che permettono la ripetizione di un gruppo di istruzioni un determinato numero di volte. Questi schemi prevedono generalmente un contatore che viene incrementato o decrementato ad ogni ciclo e viene esaminato a ogni iterazione. Input/Output: le operazioni di I/O si dividono in 3 principali schemi o approcci: I/O programmato, I/O interrupt draven, con DMA o con uso di processori appositi. Le operazioni essenziali sono: Input, Output, Start I/O, Test I/O. 22.Molte istruzioni contengono operandi e si pone il problema di come specificarne la posizione. L’indirizzamento è il modo in cui si ovvia a questo problema. Vi sono diverse modalità con cui si può implementare l’indirizzamento: Immediato: l’operando è esplicitamente presente nell’istruzione. Questa modalità può essere utilizzata per definire o usare costanti o valori iniziali delle variabili; Diretto: l’indirizzo dell’operando è esplicitamente presente nell’istruzione. Esso richiede solo un semplice riferimento alla memoria ed era la tecnica più utilizzata nei primi cacolatori; Indiretto: L’indirizzo dell’operando è contenuto in una cella di memoria il cui indirizzo è esplicitato nell’istruzione. Se da un lato si ha uno spazio di indirizzamento maggiore, dall’altro sono necessari ben due accessi alla memoria; Registro: l’istruzione contiene un riferimento a un registro in cui è presente l’operando. Lo svantaggio principale è la limitata presenza di registri all’interno di un calcolatore; Registro indiretto: in questo caso all’interno del registro è contenuto l’indirizzo dell’operando che a sua volta è contenuto in memoria. Con spiazzamento: tale tecnica richiede che l’istruzione abbia due campi indirizzo, dei quali almeno uno esplicito. Il valore A è usato direttamente mentre l’altro si riferisce ad un registro il cui contenuto viene sommato ad A per produrre l’indirizzo effettivo. Esso si divide in: o Relativo: Il registro implicitamente referenziato è il Program Counter (PC); o Registro-base: il registro referenziato contiene un indirizzo di memoria; o Indicizzato: il campo indirizzo contiene un riferimento in memoria, mentre il registro contiene uno spiazzamento all’indirizzo precedentemente specificato. A pila: tramite il registro Stack Pointer (SP) si ottiene un riferimento al primo elemento della pila (stack). Essa contiene una sequenza lineare di locazioni di memoria. 23.La paginazione consiste nella divisione concettuale della memoria fisica in pagine dalla dimensione fissa chiamate pagine fisiche. Lo spazio d’indirizzamento, a sua volta, viene suddiviso in pagine virtuali della stessa dimensione di quelle fisiche. Il meccanismo di traduzione fa corrispondere indirizzamenti all’interno di pagine virtuali ad indirizzamenti in pagine fisiche. Ogni pagina, inoltre, è mappata separatamente, per cui non è necessaria la contiguità delle pagine fisiche. Ogni indirizzo all’interno di un processo è diviso in: numero di pagina (bit più significativi), spiazzamento (bit meno significativi). Il sistema operativo tiene traccia della corrispondenza tra pagine virtuali e pagine fisiche mediante la tabella delle pagine. La TDP viene costruita al momento del caricamento del processo ed ogni sua riga contiene l’indirizzo di partenza della pagina fisica in cui è allocata la corrispondente pagina virtuale. La tabella è costituita da un numero di righe pari al numero di pagine occupate. La traduzione dell’indirizzo virtuale avviene in 3 passaggi: –un meccanismo hardware divide l’indirizzo virtuale in 12 bit più significativi (numero di pagina) e 8 bit meno significativi (displacement interno alla pagina) –Il numero di pagina viene usato all’interno della TDP per ottenere il corrispondente indirizzo di pagina fisica. –L’indirizzo ottenuto, concatenato con il displacement, fornisce l’indirizzo fisico. Il SO, inoltre, tiene traccia di tutte le pagine fisiche mediante la tabella di memoria (TDM). Essa indica lo stato della pagina (libera o allocata) ed ogni riga corrisponde ad una pagina fisica. Quando un processo termina o subisce uno swapping: –restituisce tutte le pagine fisiche ad esso assegnate –la sua TDP viene eliminata Quando il processo richiedente ha uno spazio di indirizzamento non multiplo della dimensione delle pagine fisiche si crea il fenomeno della frammentazione interna della pagina. Nella paginazione viene utilizzata una lista a puntatori contenenti i numeri delle pagine fisiche: –n pagine da allocare si individuano nei primi n nodi della lista –in fase di disallocazione vengono inseriti in testa alla lista gli n nodi relativi alle pagine liberate. Vantaggi: –il tempo di allocazione e disallocazione non dipende dalla percentuale di occupazione della memoria Svantaggi: –per il singolo elemento vi è un lieve spreco di memoria e di tempo rispetto alla gestione di una tabella statica. I meccanismi HW per la paginazione vengono utilizzati per due scopi: –Risparmiare la memoria necessaria per le TDP –Velocizzare la traduzione da indirizzi virtuali a fisici Per quanto riguarda la protezione: –spazi di indirizzamento distinti vengono di norma allocati in zone disgiunge della memoria fisica; –gli accessi alla memoria sono ristretti al proprio spazio di indirizzamento; –il registro limite della TDP blocca i tentativi di accedere a pagine virtuali oltre il limite assegnato al processo –i valori dei registri sono modificati esclusivamente da istruzioni privilegiate del SO –l'aggiunta di alcuni bit alle righe delle TDP consente di controllare il tipo di accesso alla pagina –nella paginazione non ha senso la protezione interna allo spazio di indirizzamento del processo Per quanto riguarda la condivisione: –una copia unica di una pagina fisica può essere mappata in molti spazi di indirizzamento –i diversi processi possono avere un tipo di accesso diverso dalla pagina –la condivisione viene riconosciuta ed effettuata da programmi di sistema, poiché la paginazione è trasparente all'utente –il codice condiviso deve essere eseguito in mutua esclusione 24.La segmentazione è uno schema di gestione della memoria che si basa sulla divisione dello spazio di indirizzamento dei processi in entità logiche che possono essere poste in aree non contigue di memoria. La segmentazione fornisce strumenti per la rilocazione dinamica, la protezione e la condivisione. Un programma eseguibile può essere suddiviso, ad esempio, in codice, dati e stack; ciascuno di questi oggetti può essere posto in un segmento diverso di dimensioni differenti. La segmentazione condivide alcune proprietà degli schemi di allocazione contigua( in quanto i dati di ogni singola entità logica devono essere posti in un'area contigua di memoria) e degli schemi allocazione non contigua( poiché i blocchi logici diversi possono essere messi in segmenti non contigui) La raccolta degli oggetti in segmenti viene predisposta dal programmatore. Ciascun segmento inizia all’indirizzo virtuale zero; Ogni segmento ha un nome che viene poi tradotto in un indirizzo in fase di caricamento in memoria; Un singolo dato all’interno del segmento viene identificato dallo “spiazzamento” relativo all’inizio del segmento cui appartiene. L’indirizzamento nella segmentazione è di tipo bidimensionale, infatti la designazione univoca di un dato o di una istruzione richiede il nome del segmento e lo spiazzamento all’interno del segmento. La memoria fisica, naturalmente, mantiene l’indirizzamento lineare, per cui è necessario un meccanismo per la traduzione degli indirizzi bidimensionali di segmenti virtuali in indirizzi fisici. Il caricamento di un processo segmentato avviene nel seguente modo: •il SO cerca di allocare N partizioni adatte per gli N segmenti in cui è suddiviso il processo; •il SO crea un descrittore di segmento registrandovi l'indirizzo fisico in cui è stato posto il segmento e la sua dimensione •l'insieme dei descrittori di segmento di un processo viene raccolto nella TDS(tabella dei descrittori di segmento) La traduzione di un indirizzo avviene nel seguente modo: •l'indirizzo bidimensionale virtuale I è tradotto in modo equivalente al meccanismo del registro base •il segment viene utilizzato per ritrovare l'indirizzo fisico del segmento nella TDS •il displacement viene sommato all'indirizzo fisico del segmento per ottenere l'indirizzo fisico richiesto •la dimensione del segmento viene utilizzata anche per controllare eventuali violazioni. Due registri HW, RBTDS e RLTDS contengono l'indirizzo di inizio e fine della TDS associata al processo in esecuzione. La protezione è garantita dai registri base e limite che non permettono al processo di entrare in altri segmenti . La condivisone è semplice e flessibile . Infatti , il segmento condiviso è mappato nella TDS in cui è specificato quali segmenti possano accedervi . I principali svantaggi invece sono la necessità di effettuare la compattazione , l'accesso duplice , una gestione più complessa della memoria e la impossibilità di far eseguire processi più grandi delle dimensioni fisiche della memoria . 25.La memoria virtuale è uno schema di gestione della memoria in cui soltanto una parte dello spazio di indirizzamento virtuale di un processo “residente” viene effettivamete caricata in memoria. Con questo tipo di gestione si ha che: la somma di tutti gli spazi di indirizzamento virtuali dei processi attivi può superare lacapacità della memoria fisica; ladimensione ammissibile per lo spazio di indirizzamento virtuale di un singolo processo può superare la capacità della memoria fisica disponibile in un sistema. Il funzionamento della memoria virtuale è analogo alla paginazione ed alla segmentazione e quindi con uso di tabelle di traduzione. La differenza sostanziale è che alcune pagine possono essere “mancanti”, per cui il processo di traduzione è più articolato. Lo schema di memoria virtuale fa uso della tabella di traduzione delle pagine (nel caso di memoria virtuale con schema a paginazione) con aggiunta di 1 bit di “presenza” che viene posto a 1 se la pagina è in memoria reale mentre viene posto a 0 se si tratta di una pagina mancante (page fault). Lo schema di memoria virtuale è implementabile solo su sistemi che supportano l'interrompibilità della singola istruzione. La gestione della memoria virtuale segue gli schemi analoghi alla paginazione o alla segmentazione già discussi, con l'aggiunta della TDF che associa al numero di pagine virtuali l'indirizzo di residenza di queste sulla memoria secondaria. Ai fini dell'efficienza della memoria virtuale l'allocazione di un sottoinsieme delle pagine virtuali su pagine fisiche richiede l'applicazione di specifiche strategie. Tali strategie si possono classificare in: •strategie di allocazione: quanta memoriale reale bisogna allocare a ciascun processo •strategie di ricerca: quali oggetti trasferire e quando dalla memoria secondaria a quella centrale •strategie di sostituzione: in mancanza di spazio, quali oggetti rimuovere per assegnare spazio alle nuove richieste •strategie di posizionamento: dove collocare un oggetto che entra in memoria All'occorrenza di un page fault, se il gestore della memoria non ha pagine disponibili può disporre due operazioni: •sospensione del processo che ha generato la page fault •sostituzione di una pagina in memoria ◦ALGORITMO FIFO (First In First Out): Sostituisce le pagine che da più tempo risiedono in memoria. Il gestore della memoria deve tenere traccia dell'ordine di caricamento delle pagine in memoria, ad esempio con una coda FIFO dei numeri di pagina Vantaggi: è di semplice realizzazione, richiede di aggiornare la coda solo ad ogni page fault, non richiede HW specifici Difetti: La politica FIFO spesso getta via pagine più frequentemente utilizzate (perché questo metodo non tiene traccia dell'ordine di riferimento delle pagine) ◦ALGORITMO LRU(Least Recently Used): Sostituisce le pagine residenti che meno recentemente sono state utilizzate. L'LRU considera la sequenza del comportamento di un programma con l'ipotesi che la pagina meno utilizzata recentemente è quella che ha la minore probabilità di essere referenziata in futuro. Vantaggi: in media si comporta meglio dell'algoritmo FIFO Svantaggi: l'aggiornamento dello stack va effettuato ad ogni riferimento alla pagina l'organizzazione dell'LRU è tale da richiedere un supporto HW sofisticato ◦ALGORITMO di Belady: Sostituisce le pagine che saranno referenziate nel più lontano futuro. Non è realizzabile, ma è di importanza teorica poiché consente di confrontare le prestazioni degli altri algoritmi. ◦ALGORITMO NRU (Not Recently Used): Fondato sul principio di basare le proprie decisioni sull'effettivo e misurato uso delle pagine prendendo quindi in considerazione le sequenze del comportamento di ogni programma. Le strategie di allocazione servono per deicdere quanta memoria fisica allocare a ciascun processo attivo. L'allocazione di un numero di pagine ottimale: •riduce la frequenza di page fault •riduce al minimo indispensabile il tempo di esecuzione •aumenta l'uso della CPU L'allocazione di un numero di pagine molto grande: •riduce il numero di processi attivi •abbassa il fattore di utilizzo della CPU L'allocazione di un numero di pagine troppo ridotto: •produce un aumento delle page fault •aumenta il tempo di residenza in memoria dei processi •aumenta lo spreco di CPU e dei dispositivi di I/O per il trasferimento delle pagine Un buon algoritmo di allocazione deve variare dinamicamente il numero di pagine allocate ad un processo, in base alle sue richieste ed allo stato del sistema tenendo presente: •il limite inferiore: sotto il quale l'aumento degli errori di pagina aumenta molto rapidamente •il limite superiore: oltre il quale l'allocazione di altre pagine produce un modesto miglioramento delle prestazioni La teoria del Working Set tratta in maniera interattiva l'allocazione a la sostituzione indicando: -quante pagine assegnare ad un processo -quali pagine è necessario tenere in memoria Le premesse su cui si poggia la teoria del Working set sono: •durante un qualsiasi intervallo di tempo, un processo in esecuzione favorisce un sottoinsieme delle proprie pagine •la sequenza d'accesso alla memoria da parte di un processo mostra una relazione tra il passato immediato ed il futuro •la frequenza con cui una pagina viene referenziata è una funzione variante lentamente nel tempo Questa teoria suggerisce che: •un programma deve essere in esecuzione se e solo se il suo working-set è in memoria •una pagina di memoria può essere rimpiazzata solo se non fa parte del working-set I supporti HW richiesti sono gli stessi dello schema di gestione che realizza la memoria virtuale, segmentazione o paginazione in più la memoria virtuale richiede i supporti per l'aggiornamento di: •1 bit di presenza •1 bit d'uso Infine si può affermare che la memoria virtuale consente di variare il numero di processi attivi e diminuire la memoria sprecata e parti di codice dei processi mai utilizzate non vengono mai caricate in memoria. 26.Per memorizzare grandi quantità di informazioni, rendere la memoria permanente e dare la possibilità a più processi di accedere alle stesse informazioni è necessario registrare tali informazioni in dischi o altri supporti in unità dette file. Il sistema operativo consente la gestione dei file mediante il modulo di gestione del File System. Oltre al contenuto proprio del file, il file system gestisce informazioni complementari relative al file come: struttura, tipo di accesso, nome, protezione, ecc. I file consentono di ritrovare le informazioni che contengono mediante il proprio nome sul supporto in cui risiedono. Il nome dle file si suddivide generalmente in “nome” ed “estensione”. Quest’ultima indica un particolare tipo di file, ad esempio “txt” o “c”, ecc. I file contengono le informazioni in tre tipi di strutture: –sequenza non strutturata di byte: consente la massima flessibilità al programma utente –-sequenza di record a lunghezza fissa (non più molto utilizzata) –albero di record con campo chiave (utilizzata sui grossi mainframe) Attualmente esistono diversi tipi di file: File regolari: contengono le informazioni dell’utente; Directory: conservano la struttura del file system ed informazioni sui file regolari; File speciali a caratteri: sono usati per modellare unita di I/O; File speciali a blocchi: sono utilizzati per modellare unità di I/O a blocchi come i dischi. Le informazioni su file sono generalmente contenute in due formati: codice ASCII e codice binario. Le modalità di lettura di un file sono di due tipi: sequenziale e casuale. Sequenziale quando i byte sono letti uno dopo l’altro, causale quando l’accesso al blocco di informazioni avviene in maniera diretta. I SO associano ai file altre informazioni come: data e ora della creazione, proprietario, dimensione. Alcuni SO consentono di mappare un file in memoria, ossia di caricarlo tutto o in parte, assegnandoli degli indirizzi virtuali. 27.La File Allocation Table (FAT) è un file system sviluppato per sistemi operativi DOS e Microsoft Windows. Esso si basa sulla tecnica di allocazione a lista concatenata con indice. Quest’ultima assegna ai file blocchi di disco non necessariamente contigui e mantiene l’elenco dei blocchi assegnati in memoria mediante la tabella. I pregi di questa tecnica sono: la disponibilità dell’intero blocco per i dati e la rapidità dell’accesso diretto al blocco. Lo svantaggio principale è rappresentato dalla mole di blocchi, in quanto la grandezza della tabella in memoria centrale dipende proprio dal numero di blocchi. A differenza della FAT che è usata su sistemi MS-DOS, l’allocazione mediante uso di tabelle i-node è utilizzata su sistemi Unix. Gli i-node sono piccole tabelle che contengono: gli attributi dei file, gli indirizzi dei primi dieci blocchi assegnati ai file e tre campi che consentono l’indirizzamento dei blocchi successivi mediante blocco a singola indirezione o blocco a doppia ed a tripla indirezione. I punti di forza degli i-node sono: il ridotto spreco di spazio, la possibilità di indirizzare un enorme numero di blocchi di disco e per i file di piccole dimensioni consente di reperire rapidamente l’indirizzo dei primi blocchi. 28.Un semaforo è una variabile intera sulla quale sono possibili tre operazioni: Inizializzazione ad un valore non negativo; Operazione atomica wait(): decrementa il valore della variabile. Se questa diventa negativa, il processo che ha eseguito la wait() viene bloccato; Operazione atomica signal(): incrementa il valore della variabile. Se il valore della variabile è negativo, uno dei processi bloccati sull’operazione di wait() viene sbloccato. Il funzionamento del semaforo avviene in diversi passaggi: Si associa un semaforo ad ogni risorsa condivisa; Il processo che vuole utilizzare una risorsa effettua un’operazione di wait(); Il processo che rilascia la risorsa effettua il signal(); La variabile numerica indica il numero di istanze di una specifica risorsa condivisa (contatore). Se la variabile è negativa, essa rappresenta il numero di processi in attesa. 29.La struttura delle istruzioni di un linguaggio assemblativo rispecchia la struttura delle istruzioni macchina, delle quali le prime forniscono una rappresentazione simbolica. Le istruzioni di linguaggio assemblativo sono composte da quattro parti: un campo etichetta, un campo per l’operazione, un campo per gli operandi e un campo per i commenti. Le etichette sono utilizzate per fornire nomi simbolici agli indirizzi e sono necessarie per definire le destinazioni alle quali portano le istruzioni che effettuano salti e per accedere alle parole di dati memorizzate mediante nomi simbolici. Il campo per l’operazione contiene un’abbreviazione simbolica del codice operativo oppure un comando per l’assemblatore stesso. Il campo per gli operandi viene utilizzato per specificare gli indirizzi e i registri utilizzati come operandi dell’istruzione macchina. Il campo commenti è il luogo in cui i programmatori possono inserire utili spiegazioni sul funzionamento del programma a beneficio di altri programmatori che, in seguito, lo potrebbero utilizzare o modificare. 30.Vi sono diversi modelli per la divisione degli stati dei processi, i più importanti sono quello a 5 stati e quello a 7 stati. Quello a 5 si suddivide in: New: viene creato il processo; (succ. in ready) il SO associa al processo il PID, alloca e costruisce le tabelle per la gestione del processo Ready: processo pronto per l’esecuzione ma in attesa dell’unità di elaborazione; (succ. in running) Running: processo in esecuzione; (può tornare in blocked o in ready o andare in exit) Blocked: il processo è in attesa del verificarsi di qualche evento; (torna in running) Exit: esecuzione del processo terminata; rilascio delle risorse. Il SO può mantenere alcune info Il modello a 7 stati, basato sulla tecnica dello swapping, è semplicemente un’evoluzione del precedente con l’aggiunta di due nuovi stati: Ready/Suspend: il processo non è bloccato e torna ad essere pronto con un trasferimento dati da disco; Blocked/Suspend: il processo è in attesa di un evento e la memoria che occupa è stata liberata con un trasferimento dati su disco. 31.Un insieme di processi è in stallo se ogni processo nell’insieme sta aspettando un evento che solo un altro processo nello stesso insieme può generare. Nessuno dei processi in stallo può passare in esecuzione, rilasciare le risorse ed essere riattivato. Per far si che si concretizzi una situazione di stallo, vi sono quattro condizioni: Ogni risorsa o è assegnata ad un solo processo o è libera; Un processo che vincola una risorsa ne può richiedere altre; I processi non possono essere forzati a rilasciare in anticipo le risorse acquisite; Vi siano almeno due processi e che ogni processo aspetta una risorsa occupata da un altro in attesa circolare. Vi sono differenti strategie per affrontare il problema dello stallo: ignorare il problema, riconoscerlo ed eliminarlo (tramite prerilascio (di una risorsa da uno dei processi) o rollback (salvataggio periodico)), impedirlo ed evitarlo (tramite l’eliminazione della condizione di risorse seriali(tramite lo spooling: spostamento di un'immagine dei lavori da svolgere in un buffer), non prerilasciabili(forzare il prerilascio), di hold&wait(richiedere risorse inizialmente) o di attesa circolare(terminazione dei processi(semplice e drastisco))). Uno stallo si può eliminare: -tramite prerilascio:si forza il rilascio di una risorsa -tramite rollback: si salva periodicamente lo stato dei processi, in caso di stallo si ripristina il processo all'ultimo stato salvato -tramite terminazione dei processi: forzare la terminazione dei processi in stallo e passare le risorse agli altri processi -tramite l'algoritmo del banchiere: prima di iniziare l'esecuzione ogni processo dichiara il massimo numero di risorse che gli sono necessarie . Per ogni richiesta , l'algoritmo controlla se la richiesta porta ad uno stallo sicuro o insicuro e solo le richieste che portano a stati sicuri sono accolte. Per evitare lo stallo: -Eliminare la condizione di risorse seriali: evitare di assegnare una risorsa quando non è strettamente necessario e far in modo che il minore numero possibile di processi possa richiedere una risorsa (si può risolvere con lo spooling: spostamento di un'immagine dei lavori da svolgere in un buffer). -eliminare la condizione di hold&wait: i processi richiedono tutte le risorse necessarie prima di iniziare -eliminare la condizione di attesa circolare: consiste nell'ordinare le risorse 32.Il MicroKernel è il nucleo del sistema operativo e ne contiene le funzioni essenziali. Tra queste funzioni vi sono: quelle che dipendono dall’hardware (interrupt e gestione I/O), quelle per la comunicazione dei processi e quelle per la gestione primitiva della memoria. I principali vantaggi derivanti dal MicroKernel sono: Interfaccia uniforme: i moduli usano le stesse interfacce per le richieste al microkernel; Estensibilità: introduzione di nuovi servizi o eventuali modifiche non intaccano il microkernel; Flessibilità: a seconda delle applicazioni certe caratteristiche possono essere ridotte o potenziate; Portabilità: il cambio dell’hardware comporta solo la modifica del microkernel; Affidabilità: lo sviluppo di piccole porzioni di codice ne permette una migliore ottimizzazione; Supporto ai sistemi distribuiti: ogni servizio è identificato da un numero nel microkernel e una richiesta da client non è necessario che sappia dove si trovi il server. Il microkernel riconosce gli interrupt ma non li gestisce direttamente, esso trasforma l'interrupt in un messaggio al livello utente, che invia al processo che gestisce l'interrupt. Gestione primitiva della memoria: Un modulo esterno al microkernel mappa pagine virtuali in pagine fisiche (mapping (associare ad un riferimento un valore) conservato in memoria principale) Un'applicazione che accede ad una pagina che non si trova in memoria genera un page fault(eccezione di tipo trap, generata quando un processo cerca di accedere ad una pagina mappata nello spazio di indirizzamento virtuale, ma che non è presente nella memoria fisica) l'esecuzione passa al microkernel che invia un messaggio al paginatore comunicando la pagina richiesta la pagina viene caricata quando viene caricata la pagina il pager invia un messaggio all'applicazione 33.Un thread è un flusso di esecuzione indipendente all'interno di un processo. Esso condivide lo spazio di indirizzamento con gli altri thread del processo ed è rappresentato da un TCB. Vantaggi dei thread: - Un programma può continuare la computazione anche se un suo thread è bloccato -Condivisione delle risorse: i thread condividono per definizione la memoria e le risorse del processo che li genera -Economia: Come visto la creazione e il context switch di processi sono più onerosi di quelli dei thread -Scalabilità: Su architetture multiprocessore i thread possono essere eseguiti in parallelo Svantaggi: -Difficoltà ad ottenere risorse private -Pericolo di interferenza User-level (M:1): thread all'interno del processo utente gestiti da una libreria specifica -sono gestiti senza l'aiuto del kernel -lo switch non richiede chiamate al kernel Vantaggi: risparmio di sovraccarico, schedulazione diversa per ogni applicazione, ULT eseguito da qualsiaso SO Svantaggi: chiamata a sistema da parte di un thread blocca tutti i thread del processo, non si può avere multiprocessing a livello di thread Kernel-level (1:1): gestione dei thread affidata al kernel tramite chiamate di sistema. Vantaggi: Il lavoro di gestione dei threads è svolto dal kernel. Svantaggi: Overhead: trasferimento del controllo da un thread ad un altro richiede l'intervento del kernel. 34.Prima di sviluppare il vero e proprio algoritmo di Dekker vi sono stati quattro tentativi: Protocollo dell’iglù: prima di entrare nella sezione critica i processi controllano uno alla volta una variabile turno. Se da una parte quelo protocollo garantisce la mutua esclusione, dall’altra i processi devono osservare l’alternanza e se un processo fallisce nella propria sezione critica, l’altro rimarrà bloccato per sempre; Secondo tentativo: ogni processo ha un flag relativo all’utilizzo della risorsa e può leggere il flag dell’altro senza modificarlo. Anche questo presenta due contro: se un processo fallisce nella sua sezione critica l’altro rimane bloccato e se entrambi vedono l’altro flag false entrano entrambi in sezione critica; Terzo tentativo: Anche il terzo tentativo presenta problemi analoghi ai precedenti ed in più, basandosi sul setting iniziale del flag a true, si può avere uno stallo; Quarto tentativo: viene aggiunto un ciclo di controllo sull’altro flag ma ciò restituisce una situazione si stallo parziale, poichè chi ne esce prima va in sezione critica, inoltre presenta il problema dei tentativi precedenti. Grazie ad una variabile turno si è arrivati ad una soluzione corretta, poichè questa specifica chi ha il diritto di insistere nel tentativo di entrare nella propria sezione critica. 35.Comandi Linux: ps –ef: mostra tutti i processi in esecuzione; pwd: mostra la directory di lavoro attuale; rmdir dir: cancella le directory vuote. Comandi MD-DOS: cls: elimina il contenuto della schermata; copy: copia uno o più fie in un’altra parte del disco; dir: visualizza l’elenco dei file e delle subdirectory di una directory.