Domanda

Ho usato una variabile statica globale e una variabile volatile statica nell'ambito del file,

entrambi sono aggiornati da un ISR e un ciclo principale e il ciclo principale controlla il valore della variabile.

qui durante l'ottimizzazione né la variabile globale né la variabile volatile sono ottimizzate. Quindi, invece di utilizzare una variabile volatile, una variabile globale risolve il problema.

Quindi è bene usare una variabile globale anziché volatile?

Qualche motivo specifico per usare la volatile statica ??

Qualsiasi programma di esempio sarebbe apprezzabile.

Grazie in anticipo ..

È stato utile?

Soluzione

Sono cose diverse. Non sono un esperto di semantica volatile. Ma penso che abbia senso ciò che è descritto qui.

Globale

Globale significa solo che l'identificatore in questione è dichiarato nell'ambito del file. Esistono diversi ambiti, chiamati funzione (dove sono definiti i goto-label), & # 64257; le (dove risiedono i globuli), blocco (dove risiedono le normali variabili locali) e prototipo di funzione (dove risiedono i parametri della funzione). Questo concetto esiste solo per strutturare la visibilità degli identificatori. Non ha nulla a che fare con le ottimizzazioni.

Static

static è una durata di archiviazione (non vedremo qui) e un modo per dare un nome dichiarato all'interno del collegamento interno dell'ambito del file. Questo può essere fatto per funzioni o oggetti richiesti solo all'interno di un'unità di traduzione. Un esempio tipico potrebbe essere una funzione help che stampa i parametri accettati e che viene chiamata solo dalla funzione main definita nello stesso .c file.

6.2.2 / 2 in una bozza C99:

  

Se la dichiarazione di un ambito & # 64257; le   identi & # 64257; er per un oggetto o una funzione   contiene la classe di archiviazione specificata & # 64257; er   statico, l'identi ha interno   linkage.

Il collegamento interno significa che l'identificatore non è visibile all'esterno dell'unità di traduzione corrente (come la funzione help di cui sopra).

volatile

Volatile è una cosa diversa: ( 6.7.3 / 6 )

  

Un oggetto che ha volatile-quali & # 64257; ed   il tipo può essere modificato in modi sconosciuti a   l'implementazione o ne hanno altri   effetti collaterali sconosciuti. Pertanto qualsiasi   espressione che si riferisce a tale oggetto   deve essere valutato rigorosamente secondo   alle regole della macchina astratta,   come descritto in 5.1.2.3. Inoltre,   ad ogni punto sequenza il valore ultimo   memorizzato nell'oggetto deve essere d'accordo   quello prescritto dall'abstract   macchina, ad eccezione dei modi & # 64257; a cura di   fattori sconosciuti menzionati   in precedenza.

Lo standard fornisce un eccellente esempio per un esempio in cui volatile sarebbe ridondante ( 5.1.2.3/8 ):

  

Un'implementazione potrebbe de & # 64257; ne a   corrispondenza uno a uno tra   semantica astratta e attuale: a   ogni punto di sequenza, i valori di   gli oggetti reali sarebbero d'accordo   quelli specificati dall'abstract   semantica. La parola chiave volatile   sarebbe quindi ridondante.

I punti di sequenza sono punti in cui l'effetto degli effetti collaterali riguardanti la macchina astratta è completato (ovvero non sono incluse condizioni esterne come i valori delle celle di memoria). Tra destra e sinistra di & amp; & amp; e || , dopo ; e il ritorno da una chiamata di funzione sono ad esempio punti di sequenza.

La semantica astratta è ciò che il compilatore può dedurre dal vedere solo la sequenza di codice all'interno di un determinato programma. Gli effetti delle ottimizzazioni sono irrilevanti qui. La semantica effettiva include l'effetto degli effetti collaterali scritti scrivendo sugli oggetti (ad esempio, il cambio di celle di memoria). Qualificare un oggetto come volatile significa che si ottiene sempre il valore di un oggetto direttamente dalla memoria ("modificato da fattori sconosciuti"). Lo standard non menziona i thread da nessuna parte e, se è necessario fare affidamento sull'ordine delle modifiche o sull'atomicità delle operazioni, è necessario utilizzare metodi dipendenti dalla piattaforma per garantire ciò.

Per una panoramica di facile comprensione, Intel ha un ottimo articolo al riguardo qui .

Cosa devo fare ora?

Continua a dichiarare volatili i tuoi dati di ambito file (globali). Dati globali i

Altri suggerimenti

Prima di tutto lasciatemi dire che una variabile globale statica è la stessa di una variabile globale, tranne per il fatto che state limitando la variabile all'ambito del file. Cioè non puoi utilizzare questa variabile globale in altri file tramite la parola chiave extern .

Quindi puoi ridurre la tua domanda a variabili globali vs variabili volatili.

Ora su volatile:

Come const , volatile è un modificatore di tipo.

La parola chiave volatile è stata creata per prevenire ottimizzazioni del compilatore che potrebbero rendere il codice errato, in particolare in presenza di eventi asincroni.

Gli oggetti dichiarati come volatile non possono essere utilizzati in determinate ottimizzazioni.

Il sistema legge sempre l'attuale valore reale di un oggetto volatile nel punto in cui viene utilizzato, anche se un'istruzione precedente ha richiesto un valore dallo stesso oggetto. Inoltre, il valore dell'oggetto viene scritto immediatamente al momento dell'assegnazione. Ciò significa che non è possibile memorizzare nella cache una variabile volatile in un registro CPU.

Dr. Jobb's ha un ottimo articolo su volatile .

Ecco un esempio dall'articolo del Dr. Jobb:

class Gadget
{
public:
    void Wait()
    {
        while (!flag_)
        {
            Sleep(1000); // sleeps for 1000 milliseconds
        }
    }
    void Wakeup()
    {
        flag_ = true;
    }
    ...
private:
    bool flag_;
};

Se il compilatore rileva che Sleep () è una chiamata esterna, si presupporrà che Sleep () non possa modificare il valore della variabile flag_. Quindi il compilatore può memorizzare il valore di flag_ in un registro. E in tal caso, non cambierà mai. Ma se un altro thread chiama wakeup, il primo thread sta ancora leggendo dal registro della CPU. Wait () non si sveglia mai.

Quindi perché non semplicemente non memorizzare mai le variabili nei registri ed evitare completamente il problema? Si scopre che questa ottimizzazione può davvero farti risparmiare un sacco di tempo in generale. Quindi C / C ++ ti consente di disabilitarlo esplicitamente tramite la parola chiave volatile .

Il fatto sopra flag_ era una variabile membro e non una variabile globale (né globale statico) non importa. La spiegazione dopo l'esempio fornisce il ragionamento corretto anche se hai a che fare con variabili globali (e variabili globali statiche).

Un'idea sbagliata comune è che dichiarare una variabile volatile sia sufficiente per garantire la sicurezza della discussione. Le operazioni sulla variabile non sono ancora atomiche, anche se non sono "memorizzate nella cache". nei registri

volatile con puntatori:

Volatile con puntatori, funziona come const con puntatori.

Una variabile di tipo volatile int * indica che la variabile a cui punta il puntatore è volatile.

Una variabile di tipo int * volatile indica che il puntatore stesso è volatile.

Il "quotato volatile" la parola chiave suggerisce al compilatore di non fare certe ottimizzazioni sul codice che coinvolge quella variabile; se usi semplicemente una variabile globale, nulla impedisce al compilatore di ottimizzare erroneamente il tuo codice.

Esempio:

#define MYPORT 0xDEADB33F

volatile char *portptr = (char*)MYPORT;
*portptr = 'A';
*portptr = 'B';

Senza " volatile " ;, la prima scrittura potrebbe essere ottimizzata.

La parola chiave volatile indica al compilatore di assicurarsi che la variabile non verrà mai memorizzata nella cache. Tutti gli accessi ad esso devono essere effettuati in modo coerente in modo da avere un valore coerente tra tutti i thread. Se il valore della variabile deve essere modificato da un altro thread mentre si dispone di un ciclo che verifica la modifica, si desidera che la variabile sia volatile in quanto non esiste alcuna garanzia che un valore variabile normale non verrà memorizzato nella cache in un determinato punto e il ciclo supporrò che rimanga lo stesso.

Variabile volatile su Wikipedia

Potrebbero non essere diversi nel tuo ambiente attuale, ma cambiamenti sottili potrebbero influenzare il comportamento.

  • Hardware diverso (più processori, architettura di memoria diversa)
  • Una nuova versione del compilatore con una migliore ottimizzazione.
  • Variazione casuale nei tempi tra i thread. Un problema può verificarsi solo una volta su 10 milioni.
  • Diverse impostazioni di ottimizzazione del compilatore.

A lungo termine è molto più sicuro utilizzare costrutti multithreading adeguati sin dall'inizio, anche se per ora le cose sembrano funzionare senza di essi.

Ovviamente, se il tuo programma non è multi-thread, non importa.

I +1 risposta di friol. Vorrei aggiungere alcune precisazioni poiché sembrano esserci molte confusioni in diverse risposte: la volatile di C non è la volatile di Java.

Quindi, in primo luogo, i compilatori possono fare molte ottimizzazioni in base al flusso di dati del tuo programma, volatile in C lo impedisce, si assicura che tu carichi / memorizzi sempre nella posizione ogni volta (invece di usare i registri per cancellarlo ad es.). È utile quando si dispone di una porta IO mappata in memoria, come ha sottolineato Friol.

Volatile in C non ha NIENTE a che fare con cache hardware o multithreading. Non inserisce recinti di memoria e non si ha alcuna garanzia sull'ordine delle operazioni se due thread vi accedono. La parola chiave volatile di Java fa esattamente questo però: inserire i recinti di memoria dove necessario.

variabile volatile significa che il valore assegnato ad essa non è costante, vale a dire se una funzione contenente una variabile volatile "a = 10"; e la funzione aggiunge 1 in ogni chiamata di quella funzione, quindi restituirà sempre il valore aggiornato. { volatile int a = 10; a ++; } quando la funzione precedente viene richiamata più volte, la variabile a non verrà reinizializzata su 10, mostrerà sempre il valore aggiornato fino all'esecuzione del programma. 1a uscita = 10 quindi 11 quindi 12 e così via.

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