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