IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Avoir un Sleep() précis pour courte durée?


Sujet :

C++

  1. #1
    Candidat au Club
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    3
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 3
    Par défaut Avoir un Sleep() précis pour courte durée?
    Bonjour,
    pour une appli en C/C++, j'aurais besoin qu'un thread se mette en pause pour une durée courte (1,2,5 ou 10ms) de facon fiable. Mon but étant de faire un simulateur, cette précision est importante.
    En faisant des tests avec des fonctions qui regarde l'heure :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    static LARGE_INTEGER freq;
    static bool init_fq(false);
     
    double current_time()
    {
     if (!init_fq) {
      QueryPerformanceFrequency(&freq);
      init_fq = true;
     }
     QueryPerformanceCounter(&count);
     
    return static_cast<double>(count.QuadPart) / freq.QuadPart;
    }
     
    void attendre(unsigned long time){
     double start = 1000*current_time(); // en millisecondes.
     Sleep(1);
     printf("TIME after: %f\n",1000*current_time()-start);
    }
    Je vois qu'un sleep(1) dure environs 1.8 ms (l'appel de la fonction current_time est négligeable, de l'ordre de la centime de millisecondes)
    un Sleep(2) dure 2.8ms également en moyenne (avec des rares pointes à 17-33ms).
    J'ai lu de nombreuses fois sur le net que les sleep courts sont imprécis (et je l'ai bien constaté) puisqu'ils bloquent le thread pour une durée minimale.

    Pour contourner ce problème, j'ai essayé un truc du genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void attendre(unsigned long time){
     double start = 1000*current_time(); // en millisecondes.
     SetThreadPriority(GetCurrentThread(),15);
     
     while (1000*current_time() < (start+time)){
     }
     
     SetThreadPriority(GetCurrentThread(),0);
     printf("TIME after: %f\n",1000*current_time()-start);
    }
    J'arrive à obtenir des temps d'attentes tout à fait raisonnables (1.00ms) et assez stable, mais j'ai également des pointes ponctuelles au dela des 10-20ms d'attentes.
    Le fait de changer de priorité le thread n'a en fait que peu d'influence, surtout que le but n'est pas de bloquer le reste de la machine sur laquelle tourne une application serveur video et une socket de réception sur un thread parallèle.

    J'ai meme essayé de combiner un Sleep(1) puis while (1000*current_time() < (start+time)) (pour une attente de 2ms par exemple..) Là encore je suis la plupart du temps stable, mais avec les mêmes pointes.

    Y a-t-il une solution pour éviter d'avoir des pointes d'attentes si élevée ou moins fréquement?

    Le fait d'avoir 3 choses qui tournent en même temps sur le pc (Win XPau passage) est surement une des clés du problèmes, mais pas de la solution.
    Passer sur un ensemble complètement linéaire (serveur+socket+appli en un seul thread) résoudrait-il le problème?(ou alors de toute facon, le fait d'avoir windows et n'importe quoi derrière ca plante tout..?)

  2. #2
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    14
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 14
    Par défaut
    J'ai déja eu à traiter un problème (sous linux) qui m'a confronté à l'imprécision des Sleep.

    Le problème n'est pas tant dans le fait de chercher à magouiller sur le Sleep (sous linux il existe un "nanosleep" pour les Sleep de courte duré, à voir sous windows, mais ça ne change rien au problème), c'est dans la façon dont l'ordonnanceur de ton OS gère ses processus, et tu ne peux pas énormèment intervenir dessus. Au mieux tu dois pouvoir influencer sur sa priorité voir sur la façon dont il gère l'ordonancement de processus.

    Pour info sur mon problème (en espérant que ça t'aide), la principale perte de précision dans les Sleep venait du temps nécessaire à l'OS pour effectuer le changement de contexte (mettre le processus endormie en arrière plan, laisser éventuellement un autre s'exécuter, puis à la fin du Sleep le réveiller et recharger son contexte), cette durée était d'au minimum quelques ms, donc impossible de passer outre cette barrière et d'avoir un temps de réponse précis et déterminé. (de plus étant sur un système multi-tâche, le processus peut à tout moment être interrompue pour laisser un autre plus prioritaire s'exécuter le temps de quelques ms, pour une utilisation "bureautique" de l'informatique ça ne s'y connais pas, mais pour faire de la précision c'est catastrophique puisque les temps d'exécution varieront nécessairement de quelques ms, c'est pour ça qu'il existe des noyaux dit temps réels qui garantissent ce genre de précision)

    Pour résoudre mon problème je suis passé par un noyau temps réel (RT-linux), qui te permet de gérer de façon précise le temps, nottement en utilisant son propre gestionnaire d'intérruption (j'ai ainsi pu avoir des précisions à la microseconde).

    Je ne sais pas ce qu'il en est du temps réel sous windows, j'espère t'avoir donné une piste !

  3. #3
    Candidat au Club
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    3
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 3
    Par défaut
    Ok, merci pour tes précisions.
    Malheureusement, ca me conforte un peu dans l'idée que je peux pas faire grand chose avec windows.
    Quelqu'un a déja fait fasse à ce problème sur windows?

  4. #4
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,
    Citation Envoyé par Arateris
    Ok, merci pour tes précisions.
    Malheureusement, ca me conforte un peu dans l'idée que je peux pas faire grand chose avec windows.
    Quelqu'un a déja fait fasse à ce problème sur windows?
    Je n'ai jamais fait face à ce problème, et je n'ai aucune solution à te proposer, mais je tiens à souligner le fait que, ainsi que l'a sous entendu Espadrilles, c'est clairement insoluble sous windows...

    Ainsi qu'il l'a fait remarquer, la seule solution est de passer à un noyau (et donc à un OS) spécialement prévu pour le temps réel, et il n'y en a aucun dans la game de microsoft, du moins à ma connaissance.
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #5
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Il n'y en a pas directement dans la gamme microsoft (même si je crois que windows CE est un peu meilleur que windows en terme de stabilité du cadencement, jamais testé personnellement), mais il existe RTX qui est une sous couche à windows (un peu comme RT-Linux est une sous couche de Linux) qui peut assurer une transition plus facile.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  6. #6
    Expert confirmé

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Billets dans le blog
    3
    Par défaut
    En même temps... tout dépend de ce que tu veux faire.

    Un simulateur, c'est un peu vague (dans le monde virtuel, tout programme n'est-il pas une forme de 'simulateur' ? ).

    Par exemple, dans un jeu, la simulation graphique est schedulée ("aussi vite que possible, mais pas au dela du refresh-rate, 60Hz par exemple"), la simulation d'entrée de l'utilisateur est en général tous les 0.1s, et la physique... ca dépend.
    Un simulateur physique est en général mis à jour "au moins toutes les 0.1s, et pas au delà de 0.5s" pour des raisons de stabilité des modèles.
    A noter que certains objets du simulateur physque peuvent avoir des traitements spécifiques.

    Dans tous les cas, c'est très très rare qu'on ai besoin d'une précision de 1ms quelque part, il y a tant de facteur qui entre en jeu, que rien ne peut assurer une synchronisation de tous les éléments à 1ms ! Même les informations de la souris ne parviennent pas à ce rythme à l'utilisateur... et un écran LCD peut mettre 3/4ms à afficher le résultat.

    Le seul moment ou j'ai jamais eu besoin d'une telle précision était dans l'implémentation software d'une boucle retour vidéo.

  7. #7
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Ca m'est arrivé sur un simulateur de conduite automobile. Dans ce cas, les entrées comme par exemple le volant, demande des boucles assez fines. Dans d'autres cas, il fallait un temps de cycle plus long, mais précis à la ms, ce qui revient presque au même en terme de contraintes.

    Maintenant, c'est sur que si on n'a qu'un clavier et une souris, la donne est différente.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  8. #8
    Candidat au Club
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    3
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 3
    Par défaut
    En fait, je simule l'envoi de packets sur une liaison radio. Ces paquets peuvent être émis avec une régularité exemplaire et une période qui peut descendre à 2ms dans mon étude, c'est pourquoi j'ai besoin de simuler ce temps de transmission.

    Au final, un sleep() ou autre n'est pas vraiment une solution adéquate, premièrement aux vues de perf que ca engendre, mais également en terme de réalisme, puisque on cumule ce temps d'attente avec un temps de traitement non représentatif sur la liaison...

    Donc ma solution (plus bourrine malheureusement) est faire un compteur (objective_time) qui s'incrémente quand j'en ai besoin de mes 2ms (mathématiquement) et faire un while( current_time()<objective_time) .. (en gros!, j'ai un minimum optimisé l'affaire depuis ma définition de current_time)

    du coup, ca me permet de compenser mes temps de traitement puisque je me base sur un compteur indépendant du temps réel et si jamais une des retards du au code, la boucle ne prend aucun temps et je rattrape très vite tout ce que j'aurais du déja avoir envoyé...

    Pour info, j'avais fait des tests avec mon ancienne boucle en intégrant ce dont on a besoin de la fonction current_time() dans le while (histoire de gagner du temps) j'arrivais, sous windows et avec un serveur video en parallèle, à avoir des attentes d' 1ms avec un taux d'erreur (temps> 1.01ms) en dessous de 1%. Mais avec des pointes régulière autour de 10ms et jusqu'a 60ms.

    Merci de vos réponse en tout cas.
    Arateris.

Discussions similaires

  1. Peut-on avoir deux fichier .htaccess pour 2 urlrewriting différents pour 1 même site
    Par JackBeauregard dans le forum Serveurs (Apache, IIS,...)
    Réponses: 3
    Dernier message: 30/09/2006, 08h35
  2. Avoir deux variables constantes pour requétes sql
    Par Talies dans le forum Requêtes et SQL.
    Réponses: 18
    Dernier message: 13/06/2006, 15h17
  3. [Appli] Recherche d'un type d'objet précis pour interface
    Par superpatate dans le forum Interfaces Graphiques en Java
    Réponses: 3
    Dernier message: 05/08/2005, 12h02
  4. Fonction du genre delay, sleep, wait pour attendre 1000ms
    Par FrankOVD dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 28/06/2005, 17h17

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo