Newsgroup: it.comp.lang.c++
Titolo: Quando usare "volatile"

Ciao a tutti,
se scrivo un'applicazione multithreading, le variabili condivise da più
thread andrebbero dichiarate "volatile", vero? Altrimenti il compilatore
potrebbe tentare ottimizzazioni che non deve.
In realtà in tutte le applicazioni multithreading che ho visto finora, di
"volatile" non ho mai trovato traccia!
GRAZIE
Daniele.



Io cerco di usarlo con le variabili utilizzate contemporaneamente
(normalmente solo un intero che uso come mutex e qualche contatore).
Andrea
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
--
Andrea Griffini, Programmer
http://www.netservers.com/~agriff



Ciao
	Non sono sicuro al 100% di quello che sto per dire:
penso che volatile voglia dire che tale variabile puo'
essere modificata in modo asincrono dal programma, ad
esempio da una routine di interrupt, e quindi dice
al compilatore di andare sempre a riprendere il valore
dall'indirizzo di memoria (nel codice generato), e non
da un registro dove l'aveva messa (probabilmente).
	Per la programmazione multithreading questo
non dovrebbe essere necessario, perche' dovrebbe pensare
la lireria ed il codice di context switch a salvare i
registri prima del context switch ed a ripristinarli
e quindi il valore e' sempre nel registro giusto,
mentre il problema con la rutine di
interrupt e' che lei puo' andare a scrivere direttamente
nei registri...
ripeto non sono sicuro al 100%
ciao
	Lorenzo
-- 
+-----------------------------------------------------+
|  Lorenzo Bettini          ICQ# lbetto, 16080134     |
|  PhD student in Computer Science                    |
|  Florence - Italy         (Linux User # 158233)     |
|  Home Page        : 
http://w3.newnet.it/bettini
     |
|           
http://infostud.dsi.unifi.it/~bettini
     |
|  Mail Home        : 
lorenzo...@penteres.it
     |
|  Mail University  : 
bet...@dsi.unifi.it
            |
|  
http://www.mokabyte.it
       Java on line journal  |
|  
http://music.dsi.unifi.it
         XKlaim language  |
|  
http://www.gnu.org/software/java2html
 & cpp2html   |
+-----------------------------------------------------+

nei registri...
Una routine di interrupt che non ripristini tutti i
registri che usa e' qualcosa che non mi sembra possa
avere nessun senso. Per definizione una routine di
interrupt non sa in che contesto viene chiamata e quale
possa essere in quel contesto il significato dei registri.
Sia i context switch che gli interrupt salvano e
ripristinano tutti i registri (inoltre spesso i context
switch avvengono sotto interrupt).
Il problema del 'volatile' e' pero' diverso. Se scrivo
cose abbastanza comuni come
   while(!stop)
   {
     ...
   }
e la variabile 'stop' deve essere impostata da un altro
thread il compilatore deve essere informato che quella
variabile puo' cambiare per ragioni 'esterne'; altrimenti
potrebbe essere tentato di leggere la variabile una volta
sola e ricordarsene il valore in un registro.
Dichiarando stop come volatile si ha la garanzia che
il compilatore ricarichi la varabile ogni volta che
viene chiesto.
Su PC le cose spesso sembrano funzionare comunque ma solo
perche' i processori X86 hanno pochi registri e la vita
media di un valore in un registro e' molto breve.
Come esempio concreto ho compilato con g++ il programma:
  int stop;
  int main()
  {
    while (!stop)
    {
    }
    return 0;
  }
il loop generato e' un loop senza fine (in pratica il
compilatore continua a controllare il valore di un registro;
per verificare la cosa basta guardare il codice assembler
generato) mentre aggiungendo 'volatile' la variabile stop
viene correttamente letta ad ogni interazione.
Il BCC55 invece legge la variabile ad ogni iterazione se
la variabile e' globale e compila un loop senza fine se
si usa una variabile locale. Si tratta pero' di un
comportamento su cui non si puo' fare in generale
affidamento: compilare un loop senza fine non e' un
errore e rientra nei casi previsti.
Andrea


 avere nessun senso.
non credo che Lorenzo volesse intendere questo.
Supponiamo che la mia variabile allocata in memoria e non volatile
viene, per ragioni di ottimizzazione, trasferita in un registro dopo
essere stata letta. Successivamente un entità esterna (un driver per
esempio) modifica _in memoria_ la variabile.
Il successivo accesso da parte del programma alla variabile, unitamente
alla supposizione che il valore esatto si trovi ancora nel registro,
produce un comportamento errato.
Con volatile si forza invece la lettura sempre dalla locazione
originaria, così come traspare dal libro di Bruce Eckel (in italiano):
"La parola volatile viene utilizzata quando si legge un valore che è al
di fuori del controllo del sistema, come ad esempio un registro
aggiornato da un dispositivo hardware di comunicazione". E qui non credo
che "registro" si riferisca a "registro del processore".
Saluti,
Marcello.

che "registro" si riferisca a "registro del processore".
Il termine "al di fuori del controllo del sistema" e' un po'
fuorviante. Non e' ben chiaro quali sono i confini. Piu' corretto
sarebbe considerare variazioni esterne al codice della funzione
esecuzione (un thread dello stesso programma che sta eseguendo
un'altra funzione e' a mio parere difficilmente classificabile come
un qualcosa di "esterno al sistema").
Resta vero che a parte i casi molto semplici i mutex sono
l'unica soluzione possibile.
Anzi... in questo momento mi assale un dubbio; e' comunque
corretto accedere in lettura ad una variabile intera se
alla stessa variabile puo' accedere in scrittura un altro
thread ? Non vedo problemi di sorta se l'operazione di
lettura e' atomica e se si lavora in un sistema
monoprocessore; pero' su un sistema multiprocessore forse
la cosa non e' piu' vera. Immaginando un thread che continui
a scrivere 0/1/0/1/0/1 in una variabile e un altro thread
che legge la variabile esistono sistemi multiprocessore in
cui corro il rischio di leggere qualcosa di diverso da 0/1 ?
Non credo, ma non sono sicuro.
Andrea

 cui corro il rischio di leggere qualcosa di diverso da 0/1 ?
Non dovrebbe essere un problema, perchè entrambi i processori utilizzano lo
stesso bus per scrivere in memoria. Possono utilizzarlo solo uno alla volta,
perciò quando uno non ha ancora finito di scrivere, l'altro non può iniziare
la lettura. Almeno se ricordo bene...
Daniele.

la lettura. Almeno se ricordo bene...
Se il bus e' unico e la transazione di lettura atomica... ma non so se
si tratta di una affermazione vera in generale. Onestamente non me la
sento di dire che e' impossibile che esistano architetture in cui
questo presupposto cade (anche se effettivamente mi sembrerebbe
qualcosa di abbastanza complesso).


 wrote :
| Perdonatemi, ma non capisco perchč proteggendo la variabile col mutex, il
| compilatore non farą ottimizzazioni che compromettono il funzionamento.
il succo e' che entrambi i processi "potrebbero" scriverci sopra. e basare
il codice sull'assunto che cio' non avvenga mai e' sbagliato. Nessuno te lo
assicura.

originaria, cosě come traspare dal libro di Bruce Eckel (in italiano):
Mi daresti l'URL dove trovare questo libro ????
Grazie !!!
Fausto



Volatile significa che il valore relativo alla variabile puo` cambiare
in modo asincrono rispetto al programma.
Nel caso di variabili condivise il problema e` diverso e va trattato
con altri meccanismi (semafori, monitor...).
Paolo
-------------------------------------------
  Paolo Marotta
 
http://web.tiscalinet.it/paolo_marotta/
-------------------------------------------

avere nessun senso.
La situazione in questo caso e` diversa, poiche` la routine di
interrupt non sa da quale locazione di memoria proviene il valore
del registro... puo` ripristinare solo i valori contenuti al momento
dell'attivazione.


 ignota "g" che, ad esempio, potrebbe legalmente fare "x++".
OK, hai perfettamente ragione! Ma se la variabile non fosse globale? Ad
esempio avendo:
THREAD1(int *par):
{
...    /*  change *par ! */
}
THREAD2:
{
int i;
CreateNewThread(THREAD1, &i);  /*nuovo thread con parametro i !*/
i = 0;
int j = i;
}
In questo caso, non essendo la variabile globale, il compilatore ottimizza,
oppure riesce a capire che in qualche parte del codice c'è una chiamata ad
una funzione a cui passo il puntatore a "i" e non ottimizza?!
GRAZIE per l'aiuto!!!!
Daniele.

 con altri meccanismi (semafori, monitor...).
OK, ma anche mettendo mutex, semafori e variabili condizione, vorrei sapere
se il compilatore puň tentare di fare ottimizzazioni che mettono in crisi il
programma!
Insomma: i costrutti di sincronizzazione servono per fare in modo che si
abbia accesso alle risorse comuni in modo controllato (ad es. senza
situazioni di "corsa"). Ma come fanno questi ad impedire al compilatore di
fare ottimizzazioni pericolose?
Ad esempio, dentro ad un thread una variabile potrebbe sembrare non cambiare
mai (anche se ci metto un mutex), cosě il compilatore (es.: -o3) potrebbe
essere tentato di considerare quella variabile costante. La variabile
potrebbe poi essere modificata da un altro thread (e quindi non era
costante!).
Beh, il mutex come fa a "far desistere" il compilatore dall'eseguire
quell'ottimizzazione?
Scusatemi se proprio non capisco, ma ho bisogno che le cose mi siano
spiegate passo per passo! Insomma, io pensavo di sapere tutto su  mutex,
semafori, monitor etc... invece sembra proprio che mi sia sfuggito qualcosa
di importante!
GRAZIE
Daniele.

con altri meccanismi (semafori, monitor...).
Confesso che anche io uso dichiarare alcune variabili come
'volatile' per non dover utilizzare mutex se sono solamente
interessato alla lettura del valore. Es.
  volatile int stop;
  void mainloop()
  {
    while (!stop)
    {
      ...
    }
  }
dove la variabile 'stop' (normalmente a 0) viene impostata a
1 da un altro thread. C'e' il rischio che una cosa simile
non funzioni ?


dell'attivazione.
Hmmm... proprio non afferro ...
Non viene condivisa la frase citata ? (ovvero si pensa possa
essere sensato scrivere routine di interrupt che non ripristinano
tutti i registri ?)


tutti i registri ?)
La routine (se scritta bene) ripristina tutti i registri, ma magari
durante l'esecuzione della routine la variabile e` stata modificata
da un altro thread. Volatile dice al compilatore "anche se hai il
valore della variabile nel registro, non ti fidare di quel valore...
rileggilo direttamente dalla variabile".


interessato alla lettura del valore. Es.
Il problema della mutua esclusione si presenta tipicamente quando
piu` processi scrivono una stessa locazione di memoria; se un solo
processo scrive e gli altri leggono il problema generalmente non
sussiste.
