2012-02-29 5 views
20

Considérons le morceau de code suivant:Comment empêcher g ++ d'optimiser une boucle contrôlée par une variable pouvant être modifiée par une IRQ?

unsigned global; 
while(global); 

global est modifié dans une fonction qui est invoquée par un IRQ. Cependant, g ++ supprime le test "is-not-zero" et traduit la boucle while en une boucle sans fin.

Désactiver l'optimisation du compilateur résout le problème, mais C++ offre-t-il une construction de langage pour cela?

+0

@ Styne666: le titre est la question – Necrolis

+0

Voir aussi http://stackoverflow.com/q/7083482/594137 –

+0

@ Styne666 - ce n'est pas une bonne pratique d'écrire du code qui nécessite une configuration de compilateur spécifique pour fonctionner. Ainsi, la désactivation de l'optimisation n'est pas une option pour le code de production. – 0xbadf00d

Répondre

17

Déclarez la variable comme volatile:

volatile unsigned global; 

C'est le mot-clé qui indique au compilateur que global peut être modifié dans différents threads et toutes les optimisations doivent être désactivées pour elle.

+1

Peut-être cange "toutes les optimisations" à "certaines optimisations", car il existe encore de nombreuses optimisations qui peuvent être appliquées. Par exemple, dans 'global = 5 + 6;', votre déclaration peut impliquer que '5 + 6' ne sont pas réduits. –

+2

L'ajout du qualificateur volatile ne modifie pas l'opcode créé. Il se traduit toujours par une boucle sans fin ... – 0xbadf00d

+0

@SaschaHoll oui c'est le cas. Vous pouvez définir 'global' à' 0' sur un thread différent, et la boucle se terminera. –

0

Vous pouvez utiliser les attributs GCC sur la déclaration de fonction pour désactiver l'optimisation sur une base par fonction:

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

Voir la page GCC Function Attributes pour plus d'informations.

+0

Si la variable doit se trouver dans une section spécifique de la mémoire, utilisez 'section' [Attribut de variable] (http://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html) pour le placer correctement. Vous pourriez aussi avoir besoin de le marquer comme «volatil». –

7

Puisque vous utilisez GCC et vous dire que faire la volatile variable ne fonctionne pas, vous pouvez tromper l'optimiseur en pensant que la boucle change la variable en mentant au compilateur:

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

C'est une instruction d'assemblage en ligne qui dit qu'elle modifie la variable (elle est passée comme un opérande d'entrée-sortie). Mais il est vide, donc évidemment, il ne fait rien à l'exécution. Pourtant, l'optimiseur pense qu'il modifie la variable - les programmeurs l'ont dit, et le compilateur, interdisant la substitution d'opérande (ce qui signifie simplement remplacer un texte par un autre), ne se soucie pas vraiment du corps de l'assemblage inline et ne fera aucune choses drôles. Et comme le corps est vide et que la contrainte l'utilise comme la plus générique disponible, elle devrait fonctionner de manière fiable sur toutes les plates-formes où GCC supporte l'assemblage en ligne.

+0

Je peux confirmer, que cette astuce fonctionne réellement! Je vous remercie. –

Questions connexes