Codice rientrante
In informatica, il codice di un programma o di una routine è detto rientrante se è progettato in modo che una singola copia del codice in memoria possa essere condivisa ed eseguita contemporaneamente e senza risultati inaspettati da utenti multipli o processi separati. La programmazione rientrante è vitale per molti sistemi multitasking (vedi thread-safe).
Affinché una routine o comunque una parte di codice sia rientrante deve soddisfare questi requisiti:
- Nessuna porzione del codice possa essere alterata durante l'esecuzione (codice non automodificante);
- Il codice non deve richiamare nessuna routine che non sia a sua volta rientrante. Per esempio molte implementazioni delle funzioni malloc() e free() in C non lo sono (stesso discorso per new e dispose in Pascal) e non devono essere utilizzate. In caso sia necessario allocare memoria si potrebbero utilizzare le API di sistema (dopo averne consultato la documentazione per avere la certezza che siano rientranti), che, potendo in teoria essere chiamate in qualsiasi momento e in qualsiasi situazione (perlomeno in un sistema pienamente multitasking) offrono maggiori garanzie.
- Il codice deve usare, se necessarie, solo variabili temporanee allocate sullo stack.
- Il codice non deve modificare né variabili globali né aree di memoria condivisa né impiegare variabili locali statiche.
Se una data porzione di codice non rispetta queste regole, non è possibile farla eseguire da più processi contemporaneamente ma è necessario regolarne l'accesso tramite semafori o sezioni critiche, per assicurarsi che venga eseguita da un solo processo alla volta.
La parte di codice dei kernel che implementa la sincronizzazione interprocesso (semafori, sezioni critiche ecc.) non è rientrante per definizione.
Il kernel dei sistemi operativi Windows NT è completamente rientrante, a differenza di quello di Windows 9x, le cui notevoli porzioni di codice a 16 bit derivate da MS-DOS non sono rientranti. Pertanto l'accesso a codice di sistema a 16 bit in Windows 9x è regolato da una sezione critica globale, con il risultato che spesso il sistema operativo opera in maniera monotask.
Le funzioni ricorsive dovrebbero essere sempre rientranti, sebbene, con le dovute cautele, sia possibile scrivere funzioni ricorsive non rientranti.
Esempi
[modifica | modifica wikitesto]Nel frammento di codice che segue, entrambe le funzioni f()
e g()
non sono rientranti.
int g_var = 1;
int f(){
g_var = g_var 2;
return g_var;
}
int g(){
return f () 2;
}
La funzione f()
dipende dalla variabile globale g_var
; perciò, se due processi eseguono la funzione ed accedono a g_var
simultaneamente, il risultato dipende dalle tempistiche di esecuzione. Perciò, f()
non è rientrante. Neppure g()
è rientrante, perché richiama f()
che non è rientrante.
Queste sono invece funzioni rientranti:
int f(int i){
return i 2;
}
int g(int i){
return f(i) 2;
}
Collegamenti esterni
[modifica | modifica wikitesto]- Articolo "Use reentrant functions for safer signal handling" di Dipak K. Jha (in lingua inglese).