Domanda

Un compilatore non è in grado di eliminare o riordinare legge / scrive su un variabili volatile qualificato.

Ma per quanto riguarda i casi in cui le altre variabili sono presenti, che può o non può essere volatile-qualificati?

Scenario 1

volatile int a;
volatile int b;

a = 1;
b = 2;
a = 3;
b = 4;

Può il compilatore di riordino prima e la seconda, o terza e la quarta le assegnazioni?

Scenario 2

volatile int a;
int b, c;

b = 1;
a = 1;
c = b;
a = 3;

Stessa domanda, può il compilatore di riordino prima e la seconda, o terza e la quarta le assegnazioni?

È stato utile?

Soluzione

Lo standard C ++ dice (1,9 / 6):

  

Il comportamento osservabile del   macchina astratta è la sua sequenza di   legge e scrive i dati volatili e   chiamate a funzioni di libreria I / O.

Nello scenario 1, uno dei cambiamenti che proporre modifiche alla sequenza di scritture ai dati volatili.

Nello scenario 2, né cambiamento che proporre modifiche della sequenza. Quindi avere il permesso sotto il governo "come-se" (1,9 / 1):

  

... implementazioni conformi sono   necessaria per emulare (solo) la   comportamento osservabile dell'abstract   machine ...

Per dire che questo è successo, si avrebbe bisogno di esaminare il codice macchina, utilizzare un debugger, o provocare un comportamento indefinito o non specificata il cui risultato vi capita di sapere sul vostro implementazione. Ad esempio, un'implementazione potrebbe alcuna garanzia riguardo ritiene che fili contemporaneamente-esecuzione hanno della stessa memoria, ma è fuori dell'ambito dello standard C ++. Così, mentre lo standard potrebbe permettere ad un particolare codice di trasformazione, una particolare implementazione potrebbe escluderlo, per motivi che non sa se il vostro codice sta per essere eseguito in un programma multi-threaded.

Se si sceglie di usare un comportamento osservabile per verificare se il riordino è avvenuto o meno (ad esempio, la stampa i valori delle variabili nel codice sopra), poi, naturalmente, non sarebbe stato consentito dalla norma.

Altri suggerimenti

Per scenario 1, il compilatore non deve eseguire alcuna delle reorderings di cui parli. Per lo scenario 2, la risposta potrebbe dipendere da:

  • e se le variabili b e c sono visibili all'esterno della funzione corrente (essendo non locale o abbia avuto il loro indirizzo superato
  • che si parla di (a quanto pare c'è un certo disaccordo su come stringa volatile è in C / C ++)
  • l'implementazione del compilatore

(ammorbidendo la mia prima risposta), direi che se si sta a seconda certi comportamenti nello scenario 2, che avrebbe dovuto trattarlo come codice non portabile il cui comportamento su una particolare piattaforma avrebbe determinato con qualsiasi documentazione del implementazione potrebbe indicare (e se i documenti non disse nulla su di esso, allora sei fuori di fortuna con un comportamento garantito.

da C99 5.1.2.3/2 "Esecuzione del programma":

  

Accesso ad un oggetto volatile, modifica di un oggetto, modificando un file, o chiamando una funzione che fa una di queste operazioni sono effetti collaterali, che sono cambiamenti nello stato dell'ambiente di esecuzione. Valutazione di un'espressione può produrre effetti collaterali. In certi punti specificati nei punti chiamati sequenza sequenza di esecuzione, tutti gli effetti collaterali delle precedenti sono completi, senza effetti collaterali delle valutazioni successive devono essere state effettuate.

     

...

     

(punto 5) I minimi requisiti su conforme attuazione sono:

     
      
  • Nei punti di sequenza, oggetti volatili sono stabili, nel senso che gli accessi precedenti non hanno ancora verificato accessi completi e successive.
  •   

Ecco un po 'di quello Herb Sutter ha da dire circa il comportamento richiesto di volatile accessi in C / C ++ (da "volatile vs volatile" http://www.ddj.com/hpc-high-performance-computing/212701484 ):

  

per quanto riguarda vicina ordinaria legge e scrive - può quelli ancora eventuale ricambio intorno unoptimizable lettura e scrittura? Oggi, non c'è una risposta concreta portatile perché C / C ++ implementazioni compilatore variano ampiamente e non sono suscettibili di convergere in qualunque momento presto. Per esempio, un'interpretazione del ++ standard C sostiene che ordinaria legge può muoversi liberamente in entrambe le direzioni attraverso un C / C ++ lettura volatili o scrivere, ma che uno scrittura ordinaria non può muoversi a tutti attraverso un C / C ++ lettura volatili o scrivere - che renderebbe C / C ++ volatili sia meno restrittivo e più restrittive, rispettivamente, di un ordine atomico. Alcuni fornitori di compilatore di supporto di questa interpretazione; altri non ottimizzano attraverso volatili di leggere o scrivere a tutti; e altri ancora hanno le loro semantica preferiti.

E per quel che vale, Microsoft documenta quanto segue per il ++ volatile parola chiave C / C (come Microsoft-sepcific):

  
      
  • Una scrittura a un oggetto volatile (scrittura volatile) è la semantica di uscita; un riferimento a un oggetto globale o statico che si verifica prima di una scrittura a un oggetto volatile nel sequenza di istruzioni si verificherà prima che scrittura volatile nel binario compilato.

  •   
  • Una lettura di un oggetto volatile (read volatile) ha Acquisire semantica; un riferimento a un oggetto globale o statico che si verifica dopo una lettura della memoria volatile nella sequenza di istruzioni avverrà dopo tale lettura volatile nel binario compilato.

  •   
     

Questo permette oggetti volatili da utilizzare per serrature di memoria e le emissioni nella applicazioni multithread.

volatile non è un recinto di memoria. Assegnazioni a B e C in frammento # 2 possono essere eliminati o eseguire quando. Perché si vuole le dichiarazioni in # 2 per provocare il comportamento di # 1?

Alcuni compilatori per quanto riguarda gli accessi agli oggetti volatili qualificato come un recinto di memoria. Gli altri non lo fanno. Alcuni programmi sono scritti per richiedere che le opere volatile come un recinto. Altri non sono.

Codice che è scritto a richiedere recinzioni, in esecuzione su piattaforme che forniscono loro, può funzionare meglio di codice che viene scritto non richiedono recinzioni, in esecuzione su piattaforme che non forniscono loro, ma il codice che richiede recinzioni saranno malfunzionamento se non sono forniti. Codice che non richiede recinti spesso eseguire più lenta su piattaforme che forniscono loro quanto sarebbe codice che richiede le recinzioni, e le implementazioni che forniscono recinzioni verrà eseguito tale codice più lentamente rispetto a quelli che non lo fanno.

Un buon approccio potrebbe essere quello di definire una semi_volatile macro come espansione per nulla nei sistemi in cui volatile implica una recinzione memoria, o volatile nei sistemi in cui non lo fa. Se le variabili che devono avere accessi ordinate rispetto ad altre variabili volatile ma non tra loro sono qualificati come semi-volatile, e quella macro è definita correttamente, un funzionamento affidabile sarà raggiunto su sistemi con o senza recinzioni di memoria, e il funzionamento più efficiente può essere realizzato su sistemi con recinzioni sarà raggiunto. Se un compilatore in realtà implementa un qualificatore che funziona come richiesto, semivolatile, potrebbe essere definito come una macro che utilizza tale qualificazione e di raggiungere ancora meglio il codice.

IMHO, che è una zona dello Standard in realtà dovrebbe affrontare, dal momento che i concetti coinvolti sono applicabili su molte piattaforme, e qualsiasi piattaforma dove le recinzioni sono trascurabili può semplicemente ignorarli.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top