But du temps (1); déclaration en C

Quel est le but while(1); servir ? Je suis conscient du fait while(1) (pas de point-virgule) boucle à l’infini et est similaire à une situation de spinlock. Cependant, je ne vois pas où while(1); peut être utilisé ?

Code exemple

 if(!condition) { while(1); } 

Note: Ceci n’est pas un cas de dowhile() ou plain while(1) .

S’il vous plaît noter que toutes les déclarations valables de la langue ne doivent pas servir un but. Ils sont valables selon la grammaire de la langue. On peut construire beaucoup de déclarations “inutiles” similaires, comme if (1); . Je vois de telles déclarations comme la conjonction d’un énoncé conditionnel ( if , while , etc.) et d’un énoncé vide ; (qui est également une déclaration valable même si elle ne sert manifestement pas de but spécifique).

Cela dit, j’ai rencontré while (1); en code de sécurité. Lorsque l’utilisateur fait quelque chose de très mauvais avec un périphérique embarqué, il peut être utile de l’empêcher d’essayer autre chose. Avec while (1); , nous pouvons bloquer inconditionnellement un appareil jusqu’à ce qu’un opérateur accrédité le redémarre manuellement.

while(1); peut également faire partie de l’implémentation d’une panique du kernel, bien qu’une boucle for(;;) {} semble être un moyen plus courant d’exprimer la boucle infinie, et qu’il pourrait y avoir un corps non vide (par exemple, panic_blink() ).

Si vous vous penchez sur l’assemblage (cela est plus facile à comprendre du sharepoint vue des systèmes embarqués, ou si vous avez essayé de programmer un chargeur de démarrage)

vous vous rendrez compte qu’une boucle while est juste une instruction jmp …

 (pseudo code: starting loop address) add ax, bx add ax, cx cmp ax, dx jz (pseudo code: another address location) jmp (pseudo code: starting loop address) 

Expliquons comment cela fonctionne, le processeur continuera à exécuter les instructions de manière séquentielle … peu importe quoi. Donc, au moment où il entre dans cette boucle, il appenda register bx à ax et stockera dans ax, appenda register cx à ax et stockera à ax, cmp ax, dx (cela soustrait dx de ax) location) si le drapeau zéro est défini (ce qui est un bit dans le registre des drapeaux qui sera défini si le résultat de la soustraction ci-dessus est zéro), alors jmp commence l’adresse de boucle (assez simple) et refait le tout.

La raison pour laquelle je vous ai dérangé avec toute cette assemblée est de vous montrer que cela se traduirait en C par

 int A,B,C,D; // initialize to what ever; while(true) { A = A + B; A = A + C; if((AD)==0) {break;} } // if((XY)==0){break;} is the // cmp ax, dx // jz (pseudo code: another address location) 

Imaginez donc le senario en assemblage si vous aviez juste une très longue liste d’instructions qui ne se terminait pas par un jmp (la boucle while) pour répéter une section ou charger un nouveau programme ou faire quelque chose … Finalement, le processeur atteindra le dernière instruction, puis chargez l’instruction suivante pour ne rien trouver (elle gèlera ou sortingplera alors ou quelque chose).

C’est exactement pourquoi, lorsque vous voulez que le programme ne fasse rien jusqu’à ce qu’un événement soit déclenché, vous devez utiliser une boucle while (1), de sorte que le processeur continue de sauter à sa place et ne pas atteindre cette adresse d’instruction vide. Lorsque l’événement est déclenché, il saute à l’adresse des instructions du gestionnaire d’événements, l’exécute, efface l’interruption et retourne à la boucle while (1) en sautant simplement à sa place dans l’attente d’autres interruptions. Si vous voulez en savoir plus sur le while (1), appelez-le (1). Juste pour ceux qui ont terriblement envie de discuter et de commenter négativement à ce stade, ce n’est pas un tutoriel d’assemblage ou un cours. C’est simplement une explication en anglais qui est aussi simple que possible, en ignorant beaucoup de détails sous-jacents comme les pointeurs et les stacks et tout le rest, et en simplifiant les choses pour faire passer un message. Personne ne cherche l’exactitude de la documentation ici et je sais que ce code C ne se comstackra pas comme ça, mais ce n’est que pour la démonstration !!

Ceci est marqué C, mais je vais commencer par une perspective C ++. En C ++ 11, le compilateur est libre d’optimiser while(1); un moyen.

A partir du projet de norme C ++ 11 n3092, section 6.5, paragraphe 5 (c’est moi qui souligne):

Une boucle qui, en dehors de l’instruction for-init dans le cas d’une instruction for,
– ne fait aucun appel aux fonctions d’E / S de la bibliothèque et
– n’accède ni ne modifie les objects volatils, et
– n’effectue aucune opération de synchronisation (1.10) ou d’opération atomique (clause 29)
peut être supposé par l’implémentation de se terminer. [ Remarque: Ceci est destiné à autoriser les transformations du compilateur, telles que la suppression de boucles vides, même lorsque la terminaison ne peut pas être prouvée. – note finale]

La norme C11 a une entrée similaire, mais avec une différence clé. D’après le projet de norme C11 n1570, (souligné par moi):

Une instruction d’itération dont l’expression de contrôle n’est pas une expression constante , 156) qui n’effectue aucune opération d’entrée / sortie, n’accède pas aux objects volatils et n’effectue aucune synchronisation ou opération atomique dans son corps, contrôlant l’expression ou (dans le cas d’un déclaration) son expression-3 peut être supposée par l’implémentation se terminer. 157)
156) Une expression de contrôle omise est remplacée par une constante non nulle, qui est une expression constante.
157) Ceci est destiné à permettre des transformations du compilateur telles que la suppression de boucles vides, même lorsque la terminaison ne peut pas être prouvée.

Cela signifie while(1); peut être supposé se terminer en C ++ 11 mais pas en C11. Même avec cela, la note 157 (non contraignante) est interprétée par certains fournisseurs comme leur permettant de supprimer cette boucle vide. La différence entre le while(1); en C ++ 11 et C11, il s’agit de comportement défini ou non défini. Comme la boucle est vide, elle peut être supprimée en C ++ 11. En C11, while(1); est probablement non-terminante, et c’est un comportement indéfini. Puisque le programmeur a invoqué UB, le compilateur est libre de faire n’importe quoi, y compris la suppression de cette boucle incriminée.

Il y a eu un certain nombre de discussions sur le stackoverflow pour optimiser les compilateurs en supprimant while(1); . Par exemple, les compilateurs sont – ils autorisés à éliminer les boucles infinies? , Une boucle vide utilisée comme sumil sera-t-elle optimisée? , Optimisant un “while (1);” en C ++ 0x . Notez que les deux premiers étaient spécifiques à C.

Je suppose que le while(1); n’est pas associé à une boucle do

La seule implémentation semi-utile de while(1); J’ai vu une boucle do-nothing en attente d’une interruption; tel qu’un processus parent en attente d’un SIGCHLD, indiquant qu’un processus enfant est terminé. Le gestionnaire SIGCHLD du parent, une fois tous les processus enfants terminés, peut terminer le thread parent.

Il fait le tour, mais gaspille beaucoup de temps CPU. Un tel usage devrait peut-être effectuer une sorte de sumil pour renoncer périodiquement au processeur.

Une utilisation sur les logiciels embarqués consiste à implémenter une réinitialisation logicielle à l’aide du chien de garde:

 while (1); 

ou équivalent mais plus sûr car cela rend l’intention plus claire:

 do { /* nothing, let's the dog bite */ } while (1); 

Si le chien de garde est activé et n’est pas acquitté après x millisecondes, nous soaps qu’il réinitialisera le processeur. Utilisez-le pour implémenter une réinitialisation logicielle.

Un endroit que j’ai vu un while(1); est en programmation embarquée.

L’architecture a utilisé un thread principal pour surveiller les événements et les threads de travail pour les gérer. Il y avait une horloge de surveillance du matériel (explication ici ) qui effectuerait une réinitialisation logicielle du module après un certain temps. Dans la boucle d’interrogation du thread principal, il réinitialiserait ce temporisateur. Si le thread principal a détecté une erreur irrécupérable, un while(1); serait utilisé pour lier le thread principal, déclenchant ainsi la réinitialisation du chien de garde. Je crois que l’affirmation de l’échec a été mise en œuvre avec un while(1); ainsi que.

Comme d’autres l’ont dit, c’est juste une boucle infinie qui ne fait rien, complètement analogue à

 while (1) { /* Do nothing */ } 

La boucle avec le point-virgule a un corps. Lorsqu’il est utilisé en tant qu’instruction, un seul point-virgule est une instruction null et le corps de la boucle est constitué de cette instruction null.

Pour plus de lisibilité, pour que le lecteur sache que l’instruction null est le corps de la boucle, je vous recommande de l’écrire sur une ligne distincte:

 while (1) ; 

Sinon, il est facile de le rater à la fin de la ligne “while”, où il n’y a généralement pas de point-virgule, et le lecteur peut confondre la ligne suivante avec le corps de la boucle.

Ou utilisez plutôt une instruction composée vide.

 while(1); 

est en fait très utile. Surtout quand c’est un programme qui a une sorte de mot de passe à peu près et que vous voulez désactiver l’utilisation du programme pour l’utilisateur parce que, par exemple, il a entré le mauvais mot de passe trois fois. En utilisant un peu while(1); arrêterait la progression du programme et rien ne se passerait jusqu’à ce que le programme soit redémarré, principalement pour des raisons de sécurité.

Cela peut être utilisé pour attendre une interruption . Fondamentalement, vous initialisez toutes les choses dont vous avez besoin et commencez à attendre que quelque chose se produise. Après cela, une fonction spécifique est appelée et exécutée, après quoi elle retourne à l’état d’attente.

Ce truc pourrait être appuyé sur un bouton, un clic / déplacement de la souris, des données reçues, etc.

De plus, je dirais que des trucs similaires sont souvent utilisés par les frameworks d’interface utilisateur. Pendant qu’il attend des signaux sur les actions de l’utilisateur.

Dans la programmation des chipsets AVR (en utilisant le langage de programmation C), cette instruction est fréquemment utilisée, elle joue un rôle comme une boucle d’événement.

Supposons que je veuille concevoir un compteur de comptage, je peux donc utiliser ce code pour l’implémenter:

 void interrupt0() { /* check if key pressed, count up the counter */ } void main() { /* Common inits */ /* Enable interrupt capability and register its routine */ /* Event loop */ while(1); } 

Comme la condition est toujours vraie, nous pouvons dire que nous utilisons une logique de tautologie connue en mathématiques. Bien que la preuve de boucle soit toujours vraie, elle n’arrête pas de boucler à moins d’être forcée par le code ou jusqu’à ce que les ressources soient réduites.

Je pense que c’est la raison pour laquelle while(1); est utilisé est parce que plus tôt dans le code un gestionnaire d’événements ou une interruption a été défini sur ce thread. L’utilisation du code de locking standard Thread Safe peut être assez coûteuse (à temps) lorsque vous savez que votre code n’attendra que très peu de temps. Par conséquent, vous pouvez configurer l’interruption et le «spin» en utilisant while(1); qui, bien qu’il s’agisse d’une attente occupée (ne laisse pas le CPU Idle / Service autres threads) prendre très peu de cycles à configurer.

En résumé, c’est un spinlock «bon marché» pendant que votre thread attend une interruption ou un événement.