Pourquoi nanosleep () et usleep () sont-ils trop lents?

J’ai un programme qui génère des paquets à envoyer à un destinataire. J’ai besoin d’une méthode efficace pour introduire un petit délai entre l’envoi de chaque paquet afin de ne pas surcharger le destinataire. J’ai essayé usleep () et nanosleep () mais ils semblent être trop lents. J’ai mis en place une boucle d’attente occupée et j’ai eu plus de succès, mais ce n’est pas la méthode la plus efficace, à ma connaissance. Je suis intéressé par les expériences de quiconque essayant de faire ce que je fais. D’autres trouvent-ils que usleep () et nanosleep () fonctionnent bien pour ce type d’application?

Merci,

Danny Llewallyn

    Le comportement des fonctions de veille pour de très petits intervalles dépend fortement de la version et de la configuration du kernel.

    Si vous avez un kernel “tickless” ( CONFIG_NO_HZ ) et des timers haute résolution, vous pouvez vous attendre à ce que les CONFIG_NO_HZ soient assez proches de ce que vous demandez.

    Sinon, vous finirez généralement par dormir à la granularité de l’interruption de la timer. L’intervalle d’interruption du minuteur est configurable ( CONFIG_HZ ) – les choix courants sont 10 ms, 4 ms, 3,3 ms et 1 ms.

    En supposant que les approches de niveau supérieur que d’autres commentateurs ont mentionnées ne vous soient pas disponibles, une approche courante dans le domaine des systèmes embarqués / microcontrôleurs consiste à créer une boucle NOP de la longueur requirejse.

    Une opération NOP prend un cycle de processeur et, dans un environnement embarqué, vous savez généralement à quelle vitesse d’horloge votre processeur fonctionne. Vous pouvez donc utiliser un simple N- _NOP() conining de boucle _NOP() ou si un très court délai est nécessaire, ne le _NOP() pas. ne vous embêtez pas avec une boucle, ajoutez simplement le nombre requirejs de nops.

     regTX = 0xFF; // Transmit FF on special register // Wait three clock cycles _NOP(); _NOP(); _NOP(); regTX = 0x00; // Transmit 00 

    Cela semble être une mauvaise conception. Idéalement, le destinataire mettrait en queue les données supplémentaires qu’il recevrait, puis effectuerait le traitement séparé de son message. De cette manière, il peut gérer des rafales de données sans compter sur l’expéditeur pour limiter ses demandes.

    Mais peut-être une telle approche n’est-elle pas pratique si (par exemple) vous n’avez pas le contrôle du code du destinataire ou s’il s’agit d’une application intégrée.

    Je peux parler pour Solaris ici, dans la mesure où il utilise une timer de système d’exploitation pour réactiver les appels en veille. Par défaut, le temps d’attente minimal sera de 10 ms, indépendamment de ce que vous spécifiez dans votre usleep . Cependant, vous pouvez utiliser les parameters hires_tick = 1 ( hires_tick = 1 ms) et hires_hz = dans le fichier de configuration /etc/system pour augmenter la fréquence d’appels de réveil du minuteur.

    Au lieu de faire des choses au niveau des paquets, vous devez vous préoccuper de choses telles que le dépassement du récepteur. Pourquoi ne pas utiliser un stream TCP pour transmettre les données? Laissez TCP gérer des tâches telles que le contrôle du débit et la retransmission de paquets.

    Si vous avez déjà beaucoup investi dans l’approche par paquets, vous pouvez toujours utiliser une couche au-dessus de TCP pour extraire les paquets de données d’origine du stream TCP et les intégrer à vos fonctions existantes.