Sartomiki.net

  • Aumenta dimensione caratteri
  • Dimensione caratteri predefinita
  • Diminuisci dimensione caratteri

Processi

E-mail Stampa PDF
Valutazione attuale: / 2
ScarsoOttimo 

Task ManagerUn processo è una sequenza di operazioni effettuate da un programma in esecuzione. Un programma diventa processo nel momento in cui entra in esecuzione, anche se un programma può dividersi in più processi indipendenti. Un processo sequenziale è un processo deterministico, nel senso che dato uno stesso input viene sempre prodotto lo stesso output. Un processo è definito dal contenuto dei registri macchina, dallo stack del processo, dalla sezione dei dati e dallo heap.
Un processo si può trovare in stati di esecuzione diversi. Nello stato submit il processo recupera le risorse necessarie alla sua esecuzione. Nello stato hold esso attende che le risorse che necessita gli vengano attribuite. Nello stato ready esso è pronto per essere eseguito ed è in attesa che la CPU lo esegua. Nello stato running il processo viene eseguito dalla CPU. Nello stato waiting il processo è in attesa di un evento esterno come un'operazione di I/O. Nello stato complete il processo termina l'esecuzione e libera le risorse.
Solo un processo alla volta si può trovare nello stato di Running in un determinato momento. Il PCB fotograrfa il processo, memorizzando lo stato del processo, il PC, lo stato dei registri, la priorità, la lista delle locazioni di memoria in uso, le informazioni sulle operazioni di I/O e altre informazioni che dipendono dall'OS. Con l'utilizzo del PCB si possono gestire più processi concorrenti, e dare quindi l'impressione che la CPU svolga più operazioni contemporaneamente, quando invece attribuisce ad ogni processo in esecuzione un determinato tempo di esecuzione. Nei sistemi UNIX il PCB è implementato in C mediante la struttura task-struct.

Schedulazione
Esistono due tipi di scheduler dei processi. Quelli a lungo termine seleziona quale processo inserire nella lista dei processi pronti; quello a breve termien decide quale processo bisognerà eseguire. I processi possono essere classificati in due categorie: I/O bound, se richiedono molto tempo di esecuzione per le operazioni di I/O oppure CPU bound, se richiedono molte operazioni di calcolo. I long term scheduler devono scegliere processi di entrambe le categorie in modo equilibrato. In alcuni sistemi come quelli time-sharing si ha anche il medium time scheduler, necessario per rimyuovere dalla memoria alcuni processi per ridurre il grado di multiprogrammazione.

Creazione di processi
Un processo padre è in grado di creare processi figli che a loro volta possono creare processi figli. Questo porta alla creazione di un albero dei processi. Tutti i processi sono identificati da un process identifier (PID), univoco, normalmente intero. A seconda dell'OS padre e figli pososno condividere o no lo spazio di indirizzamento, anche solo parzialmente. Molto spesso lo spazio di indirizzamento del padre viene duplicato dal kernel, ma il figlio ha la possibilità di cambiarlo e quindi di renderlo uguale a quello del padre.
Durante l'esecuzione si possono avere due comportamenti: o il padre aspetta i figli morire, oppure concorrono.
La creazione di processi figli in UNIX è eseguita dalla system call fork che restituisce -1 se è il padre in caso di fallimento, oppure 0 se è un figlio oppure il PID del figlio nel caso in cui l'operazione vada a buon fine. Se un figlio vuole sapere l'identità del padre deve chiamare la system call pid_t getppid(void).
Il padre può attendere la morte del fliglio mediante la system call pid_t wait (int *status), oppure pid_t waitpid(pid_t pid, int *status, int options), in cui un padre attende un solo figlio di pid specificato.
execlp(comand, parametri, null) cambia lo spazio di indirizzamento con quello specificato.

Terminazione di processi
Un processo termina con la system call void exit (int status) che chiude tutti i descrittori di file, libera lo spazio di indirizzamento, salva il primo byte di status della tabella dei processi, invia un segnale di SIGCHLD al padre. Se muore un padre i figli diventano INIT con PID = 1. Se una exit è eseguita dal main si ha l'effetto di una return.
int kill (in pid, int sig) invia il segnale sig al processo specificato. Se pid è zero il segnale viene inviato a tutti i processi del gruppo, se è minore di uno viene spedito a tutti i processi di gruppo corrispondente al valore assoluto del numero.
SIGCHLD è il segnale che il kernel invia ad un processo apdre nel momento in cui un figlio muore. Tramite la funzione handler svincola il padre dall'attesa della morte del figlio.

Sospensione di processi
unsigned int sleep (unsigned int n) sospende il processo per n secondi. ritorna 0 se la sospensione è avvenuta con successo oppure ritorna il tempo per cui doveva dormire - valore al quale si è svegliato
unsigned int alarm (unsigned int n) invia una SIGALARM dopo un tempo n. Ritorna 0 se non vi erano time-out precedenti oppure il numero di secondi alla scadenza del time-out
int pause() mette il processo in attesa di un segnale qualunque

Processi indipendenti/cooperanti
Un processo è indipendente se non può essere condizionato dall'esecuzione di altri processi, nè può influenzare il comportamento di altri. Un processo cooperante, invece, può subire variazioni nella sua esecuzione a seconda del comportamento di altri.
I vantaggi della cooperazione sono la possibilità di condividere informazioni, l'incremento della velocità di calcolo (perchè i sottotask vengono eseguiti in parallelo) e la modularità. La cooperazione può essere effettuata tramite l'utilizzo di una memoria condivisa, che è una soluzione veloce, anche se bisogna verificare che non ci siano scritture contemporanee e letture nel momento in cui si sta scrivendo. e bisogna adottare un criterio comune per "capire" quali sono i dati a cui si sta facendo accesso. Un altro metodo è quello dello scambio di messaggi, utile per piccole quantità di dati e non richiede l'utilizzo delle system calls. Il paradigma che guida il concetto di processi cooperanti è quello del produttore consumatore: una soluzione al problema può essere implementata con un buffer circolare, con due puntatori uno che indica la posizione in cui si estrae (si consuma) e l'altro in cui si crea il contenuto (produttore). Ovviamente il consumatore non può consumare dati non ancora prodotti e il produttore non può creare oggetti in locazioni già occupate.

Cooperazione in C
#define N 10
typedef struct {
    ---
} item;
Item byffer[N]
int in=0;
int out =0;

Processo produttore
item nextProduced;
while(true){
    while(((in+1)%N)==out); // non fa nulla
        buffer[in]=nextProduced; //metto il dato
    in=(in+1)%N; //avanza di una posizione
}

Processo cooperante
item nextConsumed;
while(true)
    while(in==true) {
        while (in==out) //non fa nulla finchè non c'è qualcosa da leggere
            nextconsumed = buffer[out] //prelevo il dato
        out = (out+1)%N // avanzo
}


blog comments powered by Disqus
 

http://sartomiki.net/modules/mod_fuofb/assets/it/find-us-on-facebook-1.png

Follow me

Amici

Chi è online

 3 visitatori online

Siti amici

Banner

Notizie flash

Sono online un po' di appunti! A partire da calcolatori elettronici, proseguendo per introduzione alle reti telematiche e passando infine per sistemi operativi. Scrivetemi se trovate qualche errore... A breve saranno aggiunti nuovi appunti e completati quelli attuali!

PUBBLICITA'