2012-02-29 4 views
20

consideri il seguente pezzo di codice:Come impedire a g ++ di ottimizzare un ciclo controllato da una variabile che può essere modificata da un IRQ?

unsigned global; 
while(global); 

global viene modificato in una funzione che viene richiamata da un IRQ. Tuttavia, g ++ rimuove il test "is-not-zero" e traduce il ciclo while in un loop infinito.

La disattivazione dell'ottimizzazione del compilatore risolve il problema, ma C++ offre un costrutto linguistico per questo?

+0

@ Styne666: il titolo è la domanda – Necrolis

+0

Vedere anche http://stackoverflow.com/q/7083482/594137 –

+0

@ Styne666 - non è una buona pratica scrivere codice che richiede una specifica configurazione del compilatore per funzionare. Pertanto, disabilitare l'ottimizzazione non è un'opzione per il codice di produzione. – 0xbadf00d

risposta

17

dichiarare la variabile come volatile:

volatile unsigned global; 

Questa è la parola chiave che dice al compilatore che global possono essere modificate in diversi thread e tutte le ottimizzazioni dovrebbe essere spento per esso.

+1

Forse può "applicare tutte le ottimizzazioni" a "determinate ottimizzazioni", poiché ci sono ancora molte ottimizzazioni che possono essere applicate. Ad esempio, in 'global = 5 + 6;', la tua affermazione può implicare che '5 + 6' non siano ridotti. –

+2

L'aggiunta del qualificatore volatile non modifica l'opcode creato. Si traduce ancora in un loop infinito ... – 0xbadf00d

+0

@SaschaHoll sì. È possibile impostare 'global' su' 0' su un thread diverso e il ciclo terminerà. –

0

Si potrebbe utilizzare gli attributi GCC sulla dichiarazione di funzione per disattivare l'ottimizzazione su una base per funzione:

void myfunc() __attribute__((optimize(0))); 

vedere la pagina GCC Function Attributes per ulteriori informazioni.

+0

Se la variabile deve trovarsi in una specifica sezione di memoria, usare la 'sezione' [Attributo variabile] (http://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html) per posizionarla correttamente. Potrebbe anche essere necessario contrassegnarlo come "volatile". –

7

Dal momento che si sta utilizzando GCC e dire che fare la variabile volatile non funziona, si può ingannare l'ottimizzatore a pensare che il ciclo cambia la variabile da sdraiato al compilatore:

while(global) 
    asm volatile("" : "+g"(global)); 

Questo è una dichiarazione di assemblaggio inline che dice che modifica la variabile (viene trasmessa come un operando input-output). Ma è vuoto, quindi ovviamente non fa nulla in fase di runtime. Tuttavia, l'ottimizzatore pensa di modificare la variabile - lo hanno detto i programmatori, e il compilatore, tranne la sostituzione dell'operando (che significa semplicemente sostituire un testo con un altro), non si preoccupa del corpo dell'assembly inline e non lo farà cose divertenti ad esso.

E poiché il corpo è vuoto e il vincolo utilizzato è il più generico disponibile, dovrebbe funzionare in modo affidabile su tutte le piattaforme in cui GCC supporta l'assemblaggio in linea.

+0

Posso confermare che questo trucco funziona davvero! Grazie. –