2012-11-02 2 views
6

Dichiarare una variabile come "volatile" significa leggere/scrivere direttamente dalla posizione di memoria, non dalla variabile di registro. Ho una conoscenza del "punto di sequenza". Ma non capisco la dichiarazione menzionata nel titolo.Un compilatore non può spostare gli accessi alle variabili volatili attraverso i punti di sequenza; cosa significa?

Qualcuno potrebbe spiegare lo stesso, e fornire anche qualche frammento di codice?

+0

Ecco uno sfondo sui punti di sequenza - http://www.angelikalanger.com/Articles/VSJ/SequencePoints/SequencePoints.html –

+2

Significa che durante l'ottimizzazione e le passate di generazione di istruzioni, quando il codice/istruzioni possono essere diversamente riordinati , interleaved, ecc. per un'esecuzione più efficiente, le istruzioni che accedono alle variabili volatili sono notevolmente più limitate nel modo in cui possono essere influenzate. – twalberg

risposta

0

Volatile significa che la variabile può essere modificata all'esterno del programma e che il compilatore non può ottimizzare l'accesso, spostandolo in sequenze di espressioni (istruzioni) del programma. Un buon esempio di utilizzo volatile è rappresentato dai tick OS. volatile è un suggerimento per l'ottimizzatore per dire che non vogliamo che cambi il suo accesso: nell'esempio di OS tick, non vogliamo leggerlo più tardi o prima di dove è codificato.

3

Tutto questo è descritto in C11 5.1.2.3

L'esecuzione del programma

/-/

Accesso ad un oggetto volatile, modifica di un oggetto, la modifica di un file, o chiamare un funzione che fa una di queste operazioni sono tutti gli effetti , che sono cambiamenti nello stato di l'ambiente di esecuzione. La valutazione di un'espressione in generale include entrambi i calcoli del valore e l'inizio di effetti collaterali.

Sequenced prima è una, transitivo, a coppie relazione asimmetrica tra le valutazioni eseguite da un unico filo, che induce un ordine parziale tra tali valutazioni. Dato qualsiasi due valutazioni A e B, se A viene sequenziato prima B, allora l'esecuzione di A deve precedere l'esecuzione di B. ...

La presenza di un punto sequenza tra la valutazione delle espressioni A e B implica che ogni valore computazione e effetto collaterale associato con A viene sequenza prima di ogni valore computazione e effetto collaterale associato con B.

/-/

Un'implementazione effettiva necessità di non valutare parte di un'espressione se può dedurre che il suo valore non è usato e che no vengono prodotti gli effetti collaterali necessari (compresi quelli causati dal richiamo di una funzione o dall'accesso a un oggetto volatile).

/-/

dei minimi requisiti su conforme attuazione sono:

- Accessi agli oggetti volatili vengono valutate rigorosamente secondo le regole della astratto macchina.

Questo non è esattamente facile da interpretare, ma che cosa significa grosso modo in parole povere è: dal momento che l'accesso degli oggetti volatili è un effetto collaterale, il compilatore non è permesso di ottimizzare la via tali accessi, né è ha permesso di sequenziarli in un ordine diverso, che altrimenti avrebbe fatto per ottenere prestazioni migliori su una CPU con previsione cache/istruzione delle istruzioni, o semplicemente prestazioni migliori perché aveva certi valori comodamente memorizzati in alcuni registri della CPU.

(Lo standard C11 afferma esplicitamente che gli oggetti non volatili sono garantiti per essere thread-safe, il valore di un oggetto instabile dopo un cambio di contesto è un comportamento specificato.)

EDIT un esempio

dato il codice

volatile int x; 
volatile int y; 
volatile int z; 

x=i; 
y=something; 
z=i; 

poi il compilatore non è permesso di riordinare le istruzioni del file eseguibile per

x=i; 
z=i; 
y=something 

perché l'accesso a y deve essere sequenziato prima dell'accesso a z. C'è un punto di sequenza al punto e virgola. Ma se le variabili non fossero state volatili, sarebbe corretto per il compilatore riordinarle, se potesse determinare che non avrebbe influenzato il risultato del programma.

2

Si consideri l'esempio volutamente artificioso:

volatile int v = 5; 
int x; 
int y = (x=7), (x+v); 

Ricordiamo che virgola crea un punto di sequenza. Pertanto, l'assegnazione x=7 verrà completata prima che venga valutato x+v. Inoltre, poiché è vvolatile, il compilatore può non impegna che è 5 semplicemente perché non c'è alcun codice modificando v tra la sua dichiarazione e il punto di accesso: il compilatore deve generare un'istruzione per leggere v.

Tuttavia, questo lascia un'importante decisione al compilatore: quando esattamente v può essere letto? Più precisamente, sarebbe corretto leggere vprima di assegnando x?

Questo è dove la dichiarazione dalla tua domanda è disponibile in:

Un compilatore non può muovere gli accessi alle variabili volatili in tutta sequenza di punti

Essa vieta esplicitamente il compilatore dalla lettura v prima di assegnare x , perché così facendo sposterebbe l'accesso attraverso il punto di sequenza creato dall'operatore virgola. Senza questa restrizione, il compilatore sarebbe stato libero di leggere v prima o dopo l'assegnazione di x.

+0

O meglio, leggere o scrivere su una variabile volatile è un effetto collaterale e il compilatore non può spostare gli effetti collaterali tra i punti di sequenza. Il testo che "citi" non è uno standard C. – Lundin

1

Nel contesto della "macchina astratta" C++, un programma è definito dalla sequenza di accessi volatile eseguita ("comportamento osservabile"), qualsiasi altra cosa può essere modificata dall'ottimizzatore.

Ad esempio, se si dispone di una CPU con molti registri, è completamente accettabile per il compilatore memorizzare gli oggetti in essi contenuti, a meno che non vengano dichiarati volatile. Qualcuno che guarda gli accessi alla memoria eseguiti dalla CPU non vedrebbe più tutto ciò che fa il programma, ma è garantito che gli accessi allo volatile saranno lì.

Il programma è ottimizzato correttamente se produce la stessa sequenza di accessi volatile con gli stessi dati di un programma non ottimizzato.

Il concetto di punti di sequenza vive su un altro livello, ciò riguarda l'ordine delle operazioni all'interno della macchina astratta. Se si dispone di due operazioni senza punto di passaggio intermedio, non ci sono garanzie di ordinazione, motivo per cui x = 0; return x++ + x++; non ha un risultato definito.

Mettere insieme questi due concetti è difficile, perché così poco è garantito sugli accessi non-volatile. L'unico esempio che riuscivo a pensare in fretta sarebbe

int *y = ...; 
volatile int *x = ...; 
std::exception up; 

if (*y == 0) 
    throw up; 

return *x; 

Come *y non è volatile, è perfettamente accettabile per spostare gli accessi a ovunque e anche ottimizzarli, se possibile, ma in nessun caso può *x essere valutato se *y == 0.