162306a36Sopenharmony_ci.. include:: ../disclaimer-ita.rst
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci:Original: :ref:`Documentation/process/volatile-considered-harmful.rst <volatile_considered_harmful>`
462306a36Sopenharmony_ci:Translator: Federico Vaga <federico.vaga@vaga.pv.it>
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci.. _it_volatile_considered_harmful:
762306a36Sopenharmony_ci
862306a36Sopenharmony_ciPerché la parola chiave "volatile" non dovrebbe essere usata
962306a36Sopenharmony_ci------------------------------------------------------------
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ciSpesso i programmatori C considerano volatili quelle variabili che potrebbero
1262306a36Sopenharmony_ciessere cambiate al di fuori dal thread di esecuzione corrente; come risultato,
1362306a36Sopenharmony_cia volte saranno tentati dall'utilizzare *volatile* nel kernel per le
1462306a36Sopenharmony_cistrutture dati condivise.  In altre parole, gli è stato insegnato ad usare
1562306a36Sopenharmony_ci*volatile* come una variabile atomica di facile utilizzo, ma non è così.
1662306a36Sopenharmony_ciL'uso di *volatile* nel kernel non è quasi mai corretto; questo documento ne
1762306a36Sopenharmony_cidescrive le ragioni.
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ciIl punto chiave da capire su *volatile* è che il suo scopo è quello di
2062306a36Sopenharmony_cisopprimere le ottimizzazioni, che non è quasi mai quello che si vuole.
2162306a36Sopenharmony_ciNel kernel si devono proteggere le strutture dati condivise contro accessi
2262306a36Sopenharmony_ciconcorrenti e indesiderati: questa è un'attività completamente diversa.
2362306a36Sopenharmony_ciIl processo di protezione contro gli accessi concorrenti indesiderati eviterà
2462306a36Sopenharmony_cianche la maggior parte dei problemi relativi all'ottimizzazione in modo più
2562306a36Sopenharmony_ciefficiente.
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ciCome *volatile*, le primitive del kernel che rendono sicuro l'accesso ai dati
2862306a36Sopenharmony_ci(spinlock, mutex, barriere di sincronizzazione, ecc) sono progettate per
2962306a36Sopenharmony_ciprevenire le ottimizzazioni indesiderate.  Se vengono usate opportunamente,
3062306a36Sopenharmony_cinon ci sarà bisogno di utilizzare *volatile*.  Se vi sembra che *volatile* sia
3162306a36Sopenharmony_cicomunque necessario, ci dev'essere quasi sicuramente un baco da qualche parte.
3262306a36Sopenharmony_ciIn un pezzo di codice kernel scritto a dovere, *volatile* può solo servire a
3362306a36Sopenharmony_cirallentare le cose.
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ciConsiderate questo tipico blocco di codice kernel::
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci    spin_lock(&the_lock);
3862306a36Sopenharmony_ci    do_something_on(&shared_data);
3962306a36Sopenharmony_ci    do_something_else_with(&shared_data);
4062306a36Sopenharmony_ci    spin_unlock(&the_lock);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ciSe tutto il codice seguisse le regole di sincronizzazione, il valore di un
4362306a36Sopenharmony_cidato condiviso non potrebbe cambiare inaspettatamente mentre si trattiene un
4462306a36Sopenharmony_cilock.  Un qualsiasi altro blocco di codice che vorrà usare quel dato rimarrà
4562306a36Sopenharmony_ciin attesa del lock.  Gli spinlock agiscono come barriere di sincronizzazione
4662306a36Sopenharmony_ci- sono stati esplicitamente scritti per agire così - il che significa che gli
4762306a36Sopenharmony_ciaccessi al dato condiviso non saranno ottimizzati.  Quindi il compilatore
4862306a36Sopenharmony_cipotrebbe pensare di sapere cosa ci sarà nel dato condiviso ma la chiamata
4962306a36Sopenharmony_cispin_lock(), che agisce come una barriera di sincronizzazione, gli imporrà di
5062306a36Sopenharmony_cidimenticarsi tutto ciò che sapeva su di esso.
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ciSe il dato condiviso fosse stato dichiarato come *volatile*, la
5362306a36Sopenharmony_cisincronizzazione rimarrebbe comunque necessaria.  Ma verrà impedito al
5462306a36Sopenharmony_cicompilatore di ottimizzare gli accessi al dato anche _dentro_ alla sezione
5562306a36Sopenharmony_cicritica, dove sappiamo che in realtà nessun altro può accedervi.  Mentre si
5662306a36Sopenharmony_citrattiene un lock, il dato condiviso non è *volatile*.  Quando si ha a che
5762306a36Sopenharmony_cifare con dei dati condivisi, un'opportuna sincronizzazione rende inutile
5862306a36Sopenharmony_cil'uso di *volatile* - anzi potenzialmente dannoso.
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ciL'uso di *volatile* fu originalmente pensato per l'accesso ai registri di I/O
6162306a36Sopenharmony_cimappati in memoria.  All'interno del kernel, l'accesso ai registri, dovrebbe
6262306a36Sopenharmony_ciessere protetto dai lock, ma si potrebbe anche desiderare che il compilatore
6362306a36Sopenharmony_cinon "ottimizzi" l'accesso ai registri all'interno di una sezione critica.
6462306a36Sopenharmony_ciMa, all'interno del kernel, l'accesso alla memoria di I/O viene sempre fatto
6562306a36Sopenharmony_ciattraverso funzioni d'accesso; accedere alla memoria di I/O direttamente
6662306a36Sopenharmony_cicon i puntatori è sconsigliato e non funziona su tutte le architetture.
6762306a36Sopenharmony_ciQueste funzioni d'accesso sono scritte per evitare ottimizzazioni indesiderate,
6862306a36Sopenharmony_ciquindi, di nuovo, *volatile* è inutile.
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ciUn'altra situazione dove qualcuno potrebbe essere tentato dall'uso di
7162306a36Sopenharmony_ci*volatile*, è nel caso in cui il processore è in un'attesa attiva sul valore
7262306a36Sopenharmony_cidi una variabile.  Il modo giusto di fare questo tipo di attesa è il seguente::
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci    while (my_variable != what_i_want)
7562306a36Sopenharmony_ci        cpu_relax();
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ciLa chiamata cpu_relax() può ridurre il consumo di energia del processore
7862306a36Sopenharmony_cio cedere il passo ad un processore hyperthreaded gemello; funziona anche come
7962306a36Sopenharmony_ciuna barriera per il compilatore, quindi, ancora una volta, *volatile* non è
8062306a36Sopenharmony_cinecessario.  Ovviamente, tanto per puntualizzare, le attese attive sono
8162306a36Sopenharmony_cigeneralmente un atto antisociale.
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ciCi sono comunque alcune rare situazioni dove l'uso di *volatile* nel kernel
8462306a36Sopenharmony_ciha senso:
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci  - Le funzioni d'accesso sopracitate potrebbero usare *volatile* su quelle
8762306a36Sopenharmony_ci    architetture che supportano l'accesso diretto alla memoria di I/O.
8862306a36Sopenharmony_ci    In pratica, ogni chiamata ad una funzione d'accesso diventa una piccola
8962306a36Sopenharmony_ci    sezione critica a se stante, e garantisce che l'accesso avvenga secondo
9062306a36Sopenharmony_ci    le aspettative del programmatore.
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci  - I codice *inline assembly* che fa cambiamenti nella memoria, ma che non
9362306a36Sopenharmony_ci    ha altri effetti espliciti, rischia di essere rimosso da GCC.  Aggiungere
9462306a36Sopenharmony_ci    la parola chiave *volatile* a questo codice ne previene la rimozione.
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci  - La variabile jiffies è speciale in quanto assume un valore diverso ogni
9762306a36Sopenharmony_ci    volta che viene letta ma può essere lette senza alcuna sincronizzazione.
9862306a36Sopenharmony_ci    Quindi jiffies può essere *volatile*, ma l'aggiunta ad altre variabili di
9962306a36Sopenharmony_ci    questo è sconsigliata.  Jiffies è considerata uno "stupido retaggio"
10062306a36Sopenharmony_ci    (parole di Linus) in questo contesto; correggerla non ne varrebbe la pena e
10162306a36Sopenharmony_ci    causerebbe più problemi.
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci  - I puntatori a delle strutture dati in una memoria coerente che potrebbe
10462306a36Sopenharmony_ci    essere modificata da dispositivi di I/O può, a volte, essere legittimamente
10562306a36Sopenharmony_ci    *volatile*.  Un esempio pratico può essere quello di un adattatore di rete
10662306a36Sopenharmony_ci    che utilizza un puntatore ad un buffer circolare, questo viene cambiato
10762306a36Sopenharmony_ci    dall'adattatore per indicare quali descrittori sono stati processati.
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ciPer la maggior parte del codice, nessuna delle giustificazioni sopracitate può
11062306a36Sopenharmony_ciessere considerata.  Di conseguenza, l'uso di *volatile* è probabile che venga
11162306a36Sopenharmony_civisto come un baco e porterà a verifiche aggiuntive.  Gli sviluppatori tentati
11262306a36Sopenharmony_cidall'uso di *volatile* dovrebbero fermarsi e pensare a cosa vogliono davvero
11362306a36Sopenharmony_ciottenere.
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ciLe modifiche che rimuovono variabili *volatile* sono generalmente ben accette
11662306a36Sopenharmony_ci- purché accompagnate da una giustificazione che dimostri che i problemi di
11762306a36Sopenharmony_ciconcorrenza siano stati opportunamente considerati.
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ciRiferimenti
12062306a36Sopenharmony_ci===========
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci[1] https://lwn.net/Articles/233481/
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci[2] https://lwn.net/Articles/233482/
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ciCrediti
12762306a36Sopenharmony_ci=======
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ciImpulso e ricerca originale di Randy Dunlap
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ciScritto da Jonathan Corbet
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ciMigliorato dai commenti di Satyam Sharma, Johannes Stezenbach, Jesper
13462306a36Sopenharmony_ciJuhl, Heikki Orsila, H. Peter Anvin, Philipp Hahn, e Stefan Richter.
135