Back to home page

OSCL-LXR

 
 

    


0001 .. include:: ../disclaimer-ita.rst
0002 
0003 :Original: :ref:`Documentation/process/volatile-considered-harmful.rst <volatile_considered_harmful>`
0004 :Translator: Federico Vaga <federico.vaga@vaga.pv.it>
0005 
0006 .. _it_volatile_considered_harmful:
0007 
0008 Perché la parola chiave "volatile" non dovrebbe essere usata
0009 ------------------------------------------------------------
0010 
0011 Spesso i programmatori C considerano volatili quelle variabili che potrebbero
0012 essere cambiate al di fuori dal thread di esecuzione corrente; come risultato,
0013 a volte saranno tentati dall'utilizzare *volatile* nel kernel per le
0014 strutture dati condivise.  In altre parole, gli è stato insegnato ad usare
0015 *volatile* come una variabile atomica di facile utilizzo, ma non è così.
0016 L'uso di *volatile* nel kernel non è quasi mai corretto; questo documento ne
0017 descrive le ragioni.
0018 
0019 Il punto chiave da capire su *volatile* è che il suo scopo è quello di
0020 sopprimere le ottimizzazioni, che non è quasi mai quello che si vuole.
0021 Nel kernel si devono proteggere le strutture dati condivise contro accessi
0022 concorrenti e indesiderati: questa è un'attività completamente diversa.
0023 Il processo di protezione contro gli accessi concorrenti indesiderati eviterà
0024 anche la maggior parte dei problemi relativi all'ottimizzazione in modo più
0025 efficiente.
0026 
0027 Come *volatile*, le primitive del kernel che rendono sicuro l'accesso ai dati
0028 (spinlock, mutex, barriere di sincronizzazione, ecc) sono progettate per
0029 prevenire le ottimizzazioni indesiderate.  Se vengono usate opportunamente,
0030 non ci sarà bisogno di utilizzare *volatile*.  Se vi sembra che *volatile* sia
0031 comunque necessario, ci dev'essere quasi sicuramente un baco da qualche parte.
0032 In un pezzo di codice kernel scritto a dovere, *volatile* può solo servire a
0033 rallentare le cose.
0034 
0035 Considerate questo tipico blocco di codice kernel::
0036 
0037     spin_lock(&the_lock);
0038     do_something_on(&shared_data);
0039     do_something_else_with(&shared_data);
0040     spin_unlock(&the_lock);
0041 
0042 Se tutto il codice seguisse le regole di sincronizzazione, il valore di un
0043 dato condiviso non potrebbe cambiare inaspettatamente mentre si trattiene un
0044 lock.  Un qualsiasi altro blocco di codice che vorrà usare quel dato rimarrà
0045 in attesa del lock.  Gli spinlock agiscono come barriere di sincronizzazione
0046 - sono stati esplicitamente scritti per agire così - il che significa che gli
0047 accessi al dato condiviso non saranno ottimizzati.  Quindi il compilatore
0048 potrebbe pensare di sapere cosa ci sarà nel dato condiviso ma la chiamata
0049 spin_lock(), che agisce come una barriera di sincronizzazione, gli imporrà di
0050 dimenticarsi tutto ciò che sapeva su di esso.
0051 
0052 Se il dato condiviso fosse stato dichiarato come *volatile*, la
0053 sincronizzazione rimarrebbe comunque necessaria.  Ma verrà impedito al
0054 compilatore di ottimizzare gli accessi al dato anche _dentro_ alla sezione
0055 critica, dove sappiamo che in realtà nessun altro può accedervi.  Mentre si
0056 trattiene un lock, il dato condiviso non è *volatile*.  Quando si ha a che
0057 fare con dei dati condivisi, un'opportuna sincronizzazione rende inutile
0058 l'uso di *volatile* - anzi potenzialmente dannoso.
0059 
0060 L'uso di *volatile* fu originalmente pensato per l'accesso ai registri di I/O
0061 mappati in memoria.  All'interno del kernel, l'accesso ai registri, dovrebbe
0062 essere protetto dai lock, ma si potrebbe anche desiderare che il compilatore
0063 non "ottimizzi" l'accesso ai registri all'interno di una sezione critica.
0064 Ma, all'interno del kernel, l'accesso alla memoria di I/O viene sempre fatto
0065 attraverso funzioni d'accesso; accedere alla memoria di I/O direttamente
0066 con i puntatori è sconsigliato e non funziona su tutte le architetture.
0067 Queste funzioni d'accesso sono scritte per evitare ottimizzazioni indesiderate,
0068 quindi, di nuovo, *volatile* è inutile.
0069 
0070 Un'altra situazione dove qualcuno potrebbe essere tentato dall'uso di
0071 *volatile*, è nel caso in cui il processore è in un'attesa attiva sul valore
0072 di una variabile.  Il modo giusto di fare questo tipo di attesa è il seguente::
0073 
0074     while (my_variable != what_i_want)
0075         cpu_relax();
0076 
0077 La chiamata cpu_relax() può ridurre il consumo di energia del processore
0078 o cedere il passo ad un processore hyperthreaded gemello; funziona anche come
0079 una barriera per il compilatore, quindi, ancora una volta, *volatile* non è
0080 necessario.  Ovviamente, tanto per puntualizzare, le attese attive sono
0081 generalmente un atto antisociale.
0082 
0083 Ci sono comunque alcune rare situazioni dove l'uso di *volatile* nel kernel
0084 ha senso:
0085 
0086   - Le funzioni d'accesso sopracitate potrebbero usare *volatile* su quelle
0087     architetture che supportano l'accesso diretto alla memoria di I/O.
0088     In pratica, ogni chiamata ad una funzione d'accesso diventa una piccola
0089     sezione critica a se stante, e garantisce che l'accesso avvenga secondo
0090     le aspettative del programmatore.
0091 
0092   - I codice *inline assembly* che fa cambiamenti nella memoria, ma che non
0093     ha altri effetti espliciti, rischia di essere rimosso da GCC.  Aggiungere
0094     la parola chiave *volatile* a questo codice ne previene la rimozione.
0095 
0096   - La variabile jiffies è speciale in quanto assume un valore diverso ogni
0097     volta che viene letta ma può essere lette senza alcuna sincronizzazione.
0098     Quindi jiffies può essere *volatile*, ma l'aggiunta ad altre variabili di
0099     questo è sconsigliata.  Jiffies è considerata uno "stupido retaggio"
0100     (parole di Linus) in questo contesto; correggerla non ne varrebbe la pena e
0101     causerebbe più problemi.
0102 
0103   - I puntatori a delle strutture dati in una memoria coerente che potrebbe
0104     essere modificata da dispositivi di I/O può, a volte, essere legittimamente
0105     *volatile*.  Un esempio pratico può essere quello di un adattatore di rete
0106     che utilizza un puntatore ad un buffer circolare, questo viene cambiato
0107     dall'adattatore per indicare quali descrittori sono stati processati.
0108 
0109 Per la maggior parte del codice, nessuna delle giustificazioni sopracitate può
0110 essere considerata.  Di conseguenza, l'uso di *volatile* è probabile che venga
0111 visto come un baco e porterà a verifiche aggiuntive.  Gli sviluppatori tentati
0112 dall'uso di *volatile* dovrebbero fermarsi e pensare a cosa vogliono davvero
0113 ottenere.
0114 
0115 Le modifiche che rimuovono variabili *volatile* sono generalmente ben accette
0116 - purché accompagnate da una giustificazione che dimostri che i problemi di
0117 concorrenza siano stati opportunamente considerati.
0118 
0119 Riferimenti
0120 ===========
0121 
0122 [1] http://lwn.net/Articles/233481/
0123 
0124 [2] http://lwn.net/Articles/233482/
0125 
0126 Crediti
0127 =======
0128 
0129 Impulso e ricerca originale di Randy Dunlap
0130 
0131 Scritto da Jonathan Corbet
0132 
0133 Migliorato dai commenti di Satyam Sharma, Johannes Stezenbach, Jesper
0134 Juhl, Heikki Orsila, H. Peter Anvin, Philipp Hahn, e Stefan Richter.