Appunti per Scuola e Università
humanisticheUmanistiche
Appunti e tesine di tutte le materie per gli studenti delle scuole medie riguardanti le materie umanistiche: dall'italiano alla storia riguardanti le materie umanistiche: dall'italiano alla storia 
sceintificheScientifiche
Appunti, analisi, compresione per le scuole medie suddivisi per materie scientifiche, per ognuna troverai appunti, dispense, esercitazioni, tesi e riassunti in download.
tecnicheTecniche
Gli appunti, le tesine e riassunti di tecnica amministrativa, ingegneria tecnico, costruzione. Tutti gli appunti di AppuntiMania.com gratis!
Appunti
informatica
CComputerDatabaseInternetJava
Linux unixReti


AppuntiMania.com » Informatica » Appunti di linux unix » Generazione dei processi in unix

Generazione dei processi in unix




Visite: 3430Gradito:apreciate 4-stela [ Medio appunti ]
Leggi anche appunti:

Generazione dei processi in unix


GENERAZIONE DEI PROCESSI IN UNIX I processi vengono creati a mezzo della

Linux


Linux In informatica, sistema operativo di tipo Unix destinato ai personal
immagine di categoria

Scarica gratis Generazione dei processi in unix

GENERAZIONE DEI PROCESSI IN UNIX


I processi vengono creati a mezzo della ben nota istruzione FORK. FORK genera due processi concorrenti. Si noti, a questo proposito, il grafo che segue.



dati P testo


FORK


dati P testo F dati


WAIT EXEC


nuovo F nuovi

testo dati

WAIT EXIT



Proviamo a spiegarne il significato. Al processo P sono associate un'area dati e un'area testo. La FORK crea due processi che sono assolutamente concorrenti, nel senso che ognuno procede secondo il proprio flusso di controllo. Dalla figura scaturisce che padre e figlio condividono, immediatamente dopo la FORK, lo stesso testo (FORK crea infatti una copia esatta del testo originale), ma hanno aree dati differenti. Quindi, eventuali modifiche apportate dal padre alle variabili non avranno alcun effetto sulle corrispondenti variabili del figlio, e viceversa.

EXEC è una system call eseguita dal figlio, che fa sì che quest'ultimo ricopi nella propria area di testo una nuova area testo. Infatti la EXEC è accompagnata da vari parametri, incluso il codice del nuovo programma che deve essere eseguito (contemporaneamente, i dati precedenti potrebbero non avere più alcun senso e quindi potrebbe rendersi necessario usarne di nuovi). A questo punto, il figlio si sarà reso completamente indipendente dal padre.

Mediante la system call EXIT il figlio segnala al sistema la propria terminazione la 'volontà' di ricongiungersi al padre. Nel frattempo il padre aveva eseguito una WAIT che comunicava al sistema il fatto di essere in attesa della terminazione del figlio. Dunque l'esecuzione della EXIT da parte del figlio ha l'effetto di 'risvegliare' il padre, che può così ripartire.

Il padre deve trovarsi nella situazione di attesa prima che il figlio termini. Se è il figlio a terminare prima ancora che il padre abbia avuto il tempo di eseguire la sua WAIT, si dice che il figlio diventa ZOMBIE: le aree dati, testo e stack che lo riguardano vengono deallocati, ma il suo descrittore non viene eliminato della tabella dei processi fino a quando il padre non fa richiesta di ricongiungersi con il figlio. Si usa il termine 'zombie' perché si è in presenza di un puntatore al descrittore di un processo del quale, nei fatti, non è rimasto più nulla.


Esaminiamo ora più nel dettaglio ciò che avviene quando si genera un processo con la system call FORK.

All'atto della FORK saranno presenti in memoria padre e figlio. La creazione del figlio comporta l'inizializzazione di un nuovo elemento all'interno della tabella dei processi (descrittore del figlio). Nel descrittore saranno presenti tutte le informazioni e le risorse che il figlio ha ereditato dal padre, come variabili, files ai quali si ha accesso, UID, GID, PGID etc.. Padre e figlio continuano quindi la loro esecuzione.

La FORK restituisce, all'atto della sua chiamata, un valore di ritorno che è diverso per padre e figlio e che serve quindi a distinguerli. FORK restituisce il valore -1 nel caso in cui non è possibile generare un figlio, ad esempio perché si è raggiunto il massimo numero consentito di processi. Contrariamente, restituisce 0 per il processo figlio, e il PID del figlio per il padre. Sulla base del valore restituito dalla FORK sarà possibile discriminare, nelle istruzioni che seguono, il padre dal figlio.


UNIX, come è noto, è scritto in linguaggio C. Per usare tutte le primitive viste fin qui occorre includere la libreria di sistema types:


# INCLUDE < SYS / TYPES.H >


e dichiarare il valore restituito dalla FORK, che apparterrà in generale al tipo pid-t (nome del tipo predefinito utilizzato per i PID dei processi; può essere ad esempio il tipo intero). La sintassi adoperata è la seguente:


PID-T  FORK ()


Il seguente listato mostra la creazione di un processo figlio e come il codice del padre e quello del figlio vengono diversificati. Dopo la FORK, un secondo processo, il figlio, prende a seguire le istruzioni del programma; entrambi quindi controllano il valore del PID e agiscono di conseguenza.


# include < sys / types.h >

pid-t proc ;            /* dichiarata una variabile proc di tipo PID-T */

proc = FORK () ;

if (proc = = -1)      /* ERRORE: stampa di un messaggio su un determinato file

e uscita dal programma */


if (proc = = 0)        /* viene inserito qui il codice del figlio */


else /* codice del padre */



La chiamata EXEC viene effettuata per sostituire l'immagine di memoria con quella di un nuovo programma. Di esso esistono alcune varianti, ad esempio:

- EXECL: specifica il pathname del programma eseguibile che dovrà entrare il gioco e una lista di eventuali argomenti da passare al nuovo processo;

- EXECV: specifica il pathname più un vettore di puntatori ai dati sui quali il nuovo programma dovrà operare.

La sintassi di EXECL è la seguente:


INT EXECL (path, arg 0, , arg i, , arg n, (char *)0)


(char *)0 è un Null usato per terminare la lista degli argomenti. 'Path' è il pathname dell'eseguibile. Arg 0 è il puntatore al primo argomento, che poi è il nome del processo stesso. Arg i è il puntatore all'i-esimo argomento. Si ha quindi:


char *path, *arg 0, , *arg i


La sintassi di EXECV è:


INT EXECV (path, arg v)


char *path, *arg v[ ]


'arg v' è il vettore dei puntatori agli argomenti del nuovo programma.


Una funzione usualmente restituisce il valore di ritorno -1 per segnalare che la sua esecuzione ha avuto esito negativo. Così si avrà, ad esempio:


int i ;

i = EXECL ("usr/dir/prog", "prog", "uno", (char *)0) ;

if (1 = = -1) perror (" EXEC ")    /* controllo validità operazione */


Una EXEC potrebbe essere effettuata anche in un programma monoprocesso, cioè non dopo una FORK. In tal caso, l'effetto sarebbe semplicemente quello di sostituire l'area testo del programma in corso con quella di un nuovo programma (si interrompe l'esecuzione del programma in corso per eseguirne un altro).


Altre system call di questa famiglia sono [3]:


EXECLE, EXECVE: consentono di passare nella lista degli argomenti anche un vettore con tutte le variabili di ambiente.

EXECLP, EXECVP: il file dell'eseguibile deve essere cercato nella directory specificata dalla variabile di ambiente path.



Consideriamo ora la system call WAIT, la quale, come è ormai noto, comunica l'intenzione da parte di un padre di attendere la terminazione del figlio. Una volta che un processo abbia eseguito una FORK, prima o poi esso dovrà eseguire senz'altro anche una WAIT con la quale si sospenderà e si metterà in attesa che il figlio termini.

D'altronde, la terminazione del figlio può essere :

- terminazione NORMALE ;

- terminazione FORZATA : avviene in presenza di un evento che impone la terminazione del figlio, ad esempio una 'kill' da parte di un altro processo; viene restituito un segnale che indica il genere di terminazione che si è verificata.


Nel momento in cui si esegue la WAIT, le viene passata come parametro di ingresso una variabile di stato a 16 bit, indicante le caratteristiche della terminazione del figlio secondo la seguente modalità: se la terminazione è stata normale, gli 8 bit bassi (quelli 'a sinistra') contengono il valore restituito dalla EXIT, di cui si dirà in seguito, mentre gli 8 bit alti contengono degli zeri. Se la terminazione è stata forzata, gli 8 bit bassi contengono degli zeri, mentre gli 8 bit alti contengono il numero del segnale di terminazione.

Da parte sua, quando ha esito positivo la WAIT restituisce il PID del figlio terminato, mentre se ha esito negativo, o se si verifica un'interruzione, restituisce -1. Naturalmente ogni figlio ha il suo PID: in questo modo il padre può sempre sapere quale di essi è terminato.


La sintassi di WAIT è la seguente:


# INCLUDE < SYS / TYPES.H >

PID-T WAIT (STATUS)

int *status


'Status' è l'indirizzo dell'intero nel quale vengono depositate tutte le informazioni relative alla terminazione del figlio, come si è detto.


Si noti il seguente programma di esempio, che è di facile comprensione.


Pid-t pidf ;

int stat ;

if (FORK ( ))




La system call EXIT, della quale si può dire sinteticamente che causa la terminazione di un processo, ha in realtà tutta una serie di effetti:

- chiusura dei file aperti;

- restituzione di un valore agli 8 bit bassi della variabile di stato summenzionata;

- prosecuzione del padre, se quest'ultimo era in stato di WAIT,

- se il processo nel quale compare la EXIT aveva generato dei figli, essi diventano figli di INIT, un particolare processo lanciato dal kernel all'avvio del SO, che serve ad accettare i comandi utente. Eventuali gerarchie presenti fra i figli del processo terminato (figli dei figli) non viene conservata: essi diventano tutti figli indistinti di INIT;

- se il processo era il capostipite di un gruppo di processi (il suo pid è uguale al suo pgid) a tutti i processi del gruppo viene inviato un segnale di HANG UP (terminazione forzata).


La sintassi di EXIT è :


VOID EXIT (STATUS)

int status


'Status' è il valore da restituire al processo padre, e vale 0 per esito positivo. Facciamo un esempio:


main ( )


exit (0)




Per esercizio, scrivere un programma concorrente in cui vengono creati due processi, padre e figlio, e sia il figlio che il padre devono stampare il proprio PID. Si può fare uso della funzione GETPID, che restituisce sempre il PID del padre di un processo.




Perror è una funzione C che stampa un messaggio di errore (Kernighan-Ritchie, "Linguaggio C seconda edizione", pag.330).

In C l'espressione ' char *a ' è la dichiarazione di una variabile a di tipo puntatore a carattere e può essere usato per indicare l'indirizzo del primo carattere di una stringa. Ma perché si usa il tipo char anche per gli arg?

Il significato delle quattro funzioni citate non è chiaro.


Si ricordi che in C l'espressione ' & a ' significa "l'indirizzo della variabile a". È stato corretto, quindi, dichiarare stat come variabile intera (e non puntatore).

Open è una chiamata di sistema del C che permette di aprire un file e restituisce un intero (-1, al solito, in caso di errore). Oltre al nome del file ("usr/proc" nel nostro esempio), esso accetta come parametro un flag che specifica la modalità di apertura. O_rdonly, uno dei possibili flags, apre il file in sola lettura (cfr. Kernighan-Ritchie, pag. 223).

Scarica gratis Generazione dei processi in unix
Appunti su: generazione processi, https:wwwappuntimaniacominformaticalinux-unixgenerazione-dei-processi-in-un64php,



Scarica 100% gratis e , tesine, riassunti



Registrati ora

Password dimenticata?
  • Appunti superiori
  • In questa sezione troverai sunti esame, dispense, appunti universitari, esercitazioni e tesi, suddivisi per le principali facoltà.
  • Università
  • Appunti, dispense, esercitazioni, riassunti direttamente dalla tua aula Universitaria
  • all'Informatica
  • Introduzione all'Informatica, Information and Comunication Tecnology, componenti del computer, software, hardware ...