:: Riassunto capitolo 4: I processi ::
Torna alla pagina di Sistemi Operativi
Processo = unità di lavoro dei sistemi time-sharing.
SO = insieme di processi: quelli di SO, e quelli utente.
Livello informale: processo = programma in esecuzione
Processo > codice del programma, perché include
Programma = entità passiva Processo = entità attiva
2 processi possono essere associati al medesimo programma => ma sono sempre 2 diverse istanze di esecuzione dello stesso codice.
Stato del processo = rispetto all'uso del computer => la modalità del processo in rapporto all'uso del processore e delle risorse.
Ocio: sono termini arbitrari, e molti SO ne hanno di diversi o di più numerosi.
OCIO: nel singolo istante un solo processo è in esecuzione, mentre molti altri sono in attesa o pronti.
Processo = rappresentato nel SO dal Process Control Block (PCB).
Contiene:
Finora, 1 programma istanziato = 1 processo = 1 flusso di controllo di esecuzione = 1 thread.
Ma nel capitolo 5 vedremo bla bla.
Multiprogrammazione = più processi caricati in memoria per eseguirli "contemporaneamente" => lo schedulatore decide quale mettere in esecuzione.
1 processore = 1 processo in esecuzione nel singolo istante 2+ processori = 1 processo per processore.
Processo creato => infilato in una coda di lavori = contiene tutti i processi del sistema.
Processo ready => infilato nella Coda dei processi pronti
Ci sono anche altre code, eg una coda per ogni dispositivo I/O.
Quando viene selezionato per l'esecuzione dallo schedulatore, il processo viene dispatched ed è messo in esecuzione sulla CPU.
Quando è in esecuzione, può accadere che:
In pratica passa da una coda all'altra finché non termina.
Selezionare quale processo mettere in CPU = compito dello schedulatore.
Schedulatore a lungo termine = job scheduler = usato nei sistemi a lotti: sceglie tra tutti i processi quelli da eseguire dalla periferica di archiviazione.
Schedulatore a breve termine = CPU scheduler = sceglie tra i processi in memoria centrale, pronti per l'esecuzione, e alloca la CPU ad uno di essi.
Differenze tra i due: Lungo termine = eseguito raramente VS breve termine = eseguito spesso (eg 100 ms)
Processi = in un dato momento possono essere:
=> lo schedulatore a lungo termine deve scegliere un buon compromesso tra processi I/O- e CPU-bound, se no la CPU rimane inutilizzata troppo a lungo o male.
In alcuni sistemi lo schedulatore a lungo termine è assente o minimale => UNIX e Windows: tutti i processi sono gestiti dallo scheduler a breve termine => ci pensa l'utente: se le prestazioni calano troppo perché ci sono troppi processi, l'utente ne accopperà qualcuno.
Schedulatore a medio termine: introdotto in alcuni SO. => a volte è utile ridurre il grado di multiprogrammazione (quanti processi sono attualmente in memoria)
=> swapping è spostare un processo da memoria centrale a memoria di massa (swapped out), o viceversa (swapped in).
Utile ad esempio per bilanciare tra troppi I/O- o CPU-bound.
Contesto di un processo = stato di esecuzione
=> cambio di contesto = context switch = salvare lo stato di esecuzione di un processo nella PCB e caricare dalla stessa PCB il contesto di un altro processo, ed eseguirlo.
Può essere realizzato in HW o in SW.
È tempo di gestione di sistema: quando si cambia il contesto, il SO non fa niente per l'evoluzione dei processi.
È anche lento => si usano i thread per cercare di velocizzarlo o evitarlo del tutto.
Ci sono SO in cui i processi sono creati e distrutti dinamicamente, ed eseguiti in modo concorrente => occorre un meccanismo per creare e terminare i processi.
Un processo chiama il SO per creare un nuovo processo => diventa il padre di un processo figlio => se il figlio a sua volta genera, ho un albero di processi.
Processo = ha bisogno di risorse:
Se gliele dà il padre, il SO "respira" meglio.
Dati di inizializzazione: il padre può passarne quanti ne vuole al figlio, per inizializzarlo come preferisce.
Creazione di figli: 2 possibilità:
Spazio di indirizzamento del processo figlio: 2 possibilità:
Esempio di UNIX:
Terminazione normale: un processo arriva alla sua fine naturale e dice al SO di riprendersi le risorse: chiamata exit.
Terminazione anormale: per errori vari il padre chiama l'abort su di un figlio:
Un'alternativa a quest'ultimo punto è che a un processo orfano viene assegnato come padre il processo init, che è sempre in esecuzione => il figlio sa quindi dove mandare i suoi dati in output.
A che serve la cooperazione:
Esecuzione concorrente => meccanismi per comunicare e sincronizzare i processi.
Esempio di comunicazione con spazio di memoria condiviso: un buffer riempito da un processo, e svuotato da un altro processo => vanno sincronizzati per evitare che il consumatore consumi oggetti non ancora prodotti.
Buffer illimitato = il produttore scrive quanto gli pare; il consumatore legge e si ferma solo se il buffer è vuoto.
Buffer limitato = il produttore scrive e si blocca quando non c'è più spazio nel buffer: il consumatore legge e si ferma se il buffer è vuoto.
Buffer = o viene fornito dal SO, o si programma una zona di memoria condivisa tra processi.
Servono meccanismi di comunicazione tra processi = InterProcess Communication (IPC).
IPC = meccanismi per comunicare e sincronizzarsi senza condividere lo spazio di indirizzamento => miglior modo per ottenere ciò è usare il passaggio di messaggi.
Due operazioni:
Messaggi: dimensione fissa o variabile.
È necessario un canale di comunicazione tra i due processi => la realizzazione fisica del canale non ci interessa, invece guardiamo alla realizzazione logica.
Metodi per implementare logicamente le send/receive:
I processi che vogliono comunicare devono potersi identificare: in modo diretto o indiretto.
Ogni processo comunicante conosce esplicitamente l'altro.
Quindi, le primitive diventano:
Il canale che si forma in questo modo ha le seguenti proprietà:
=> indirizzamento simmetrico = ogni processo usa il nome dell'altro per comunicare.
Variante = indirizzamento asimmetrico = il mittente conosce il destinatario, ma il destinatario non conosce il mittente.
Svantaggi (sia simmetrico che asimmetrico): se cambio l'id di un processo, devo rifare il canale di comunicazione da capo.
I messaggi sono mandati attraverso mailbox o porte.
Mailbox = struttura in cui oggetti vengono depositato da qualcuno e prelevati da altri. Ogni mailbox ha il suo id.
Le primitive diventano:
Proprietà del canale così creato:
Se ci sono più processi che eseguono una receive da una mailbox, chi leggerà?
Proprietà della mailbox:
Mailbox del SO:
Mailbox del processo:
=> il proprietario è unico => non c'è confusione su chi dovrebbe leggere.
Le proprietà su una mailbox possono cmq essere trasferite ad altri processi.
Comunicazione sincrona = bloccante Comunicazione asincrona = non bloccante
Invio bloccante = il mittente si blocca finché un ricevente non legge.
Invio non bloccante = il mittente invia e torna a lavorare
Ricezione bloccante = il ricevente si blocca finché non arriva un messaggio
Ricezione non bloccante = il ricevente o acquisisce un messaggio, oppure acquisisce null, senza bloccarsi in attesa.
Se sia la send che la receive sono bloccate => c'è un rendezvous tra 2 processi.
...
...
...
Socket = il capo estremo di un canale di comunicazione.
Socket = identificato da
I server ascoltano su di un certo IP, ad una certa porta.
Client: quando inizia la connessione, il suo SO gli assegna una porta casuale (> 1024) => la comunicazione consiste nella coppia di socket:
TCP = socket orientati alla connessione UDP = socket senza connessione.
...
...