Temps d'attente précis (~ms)

Signaler
Messages postés
6
Date d'inscription
samedi 25 mars 2006
Statut
Membre
Dernière intervention
18 juillet 2007
-
Messages postés
21041
Date d'inscription
jeudi 23 janvier 2003
Statut
Modérateur
Dernière intervention
21 août 2019
-
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
:

static LARGE_INTEGER freq;
static bool 
init_fq(false);



 



double current_time()
{
     if (!init_fq) 
{
          QueryPerformanceFrequency(<wbr>&amp;freq);
          init_fq = 
true;
     }
     QueryPerformanceCounter(<wbr>&amp;count);</wbr></wbr>






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()<wbr>-start);
}

</wbr>



 



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 :



 



 void attendre(unsigned long 
time){
 double start = 1000*current_time(); // en 
millisecondes.
 SetThreadPriority(GetCurrentTh<wbr>read(),15);
 
 while 
(1000*current_time() < (start+time)){ }</wbr>



 
 SetThreadPriority(GetCurrentTh<wbr>read(),0);
 printf("TIME 
after: %f\n",1000*current_time()<wbr>-start);
}
</wbr></wbr>


 



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..?)

14 réponses

Messages postés
1100
Date d'inscription
jeudi 24 avril 2003
Statut
Membre
Dernière intervention
17 octobre 2012
7
Bonjour,

Pourquoi as-tu besoin d'un traitement toutes les millisecondes.
Tu n'es pas tout seul sur le système ;)
Soit tu lance une boucle pour conserver les ressources restantes soit tu te créé un système d'exploitation (bonne chance).

PS : Ce n'est pas à prendre sur un ton de critique mais sur un conseil disant que le système il faut bien qu'il tourne et que il y a 1000ms dans une seconde toutes ne sont pas réservés à un seul programme [vous me suivez ?].

Merci et bonne prog,
@++

Le créateur du site http://victorlogiciels.com
Messages postés
21041
Date d'inscription
jeudi 23 janvier 2003
Statut
Modérateur
Dernière intervention
21 août 2019
29
Clair qu'un système multi taches préemptif n'est pas fait pour du temps réel mais pour que l'action utilisateur ait toujours priorité.

Il faut y ajouter qu'un appel de fonction n'est pas gratuit, minimum de 4 octets PUSHés (registre EIP). Si comme ici il y a dans cette fonction 2 appels externes et une division en flottant, alors pas de quoi s'étonner qu'on se retrouve loin de la ms.

ciao...
BruNews, MVP VC++
Messages postés
1100
Date d'inscription
jeudi 24 avril 2003
Statut
Membre
Dernière intervention
17 octobre 2012
7
Bonjour,

Je ne dirais pas mieux que notre expert ASM.

Merci et bonne prog,
@++

Le créateur du site http://victorlogiciels.com
Messages postés
3874
Date d'inscription
mardi 8 mars 2005
Statut
Modérateur
Dernière intervention
7 novembre 2014
14
Salut,

Sur un processeur cadencé à 2GHz, il y a un front d'horloge toutes les 0,000.000.000.5 secondes, et 2.000.000 de fronts d'horloge par millisecondes.

Avec ces deux millions de fronts, on peut bien espérer 500.000 instructions sur un mauvais processeur, à partir du moment ou le processeur travail sans attendre le dur ou autre chose. On peut sans problème chronométrer une boucle tournant à quelques dizaines de micro secondes quand elle n'est pas interrompue par un autre thread.

Mais bon comme dit plus haut, le préamptif fait que Windows va donner du temps à d'autre thread. Il y a pas de solution gratuites sous XP (LabView...), mais y a des Linux temps réel.

La solution pour avoir du (presque) temp réel sous Windows passe probablement par la modification de la config du PIT.

A ce que j'ai compris c'est ce compteur qui est responsable de lancer
une interruption IRQ0, et cette interruption lance l'ordonanceur qui
peut avoir l'idée de choisir un autre thread.

Ce composant à pas l'air trop compliqué, mais a ce que j'ai compris, il faut passer en adressage réel pour avoir accès aux adresses qui le concerne...
Messages postés
6
Date d'inscription
samedi 25 mars 2006
Statut
Membre
Dernière intervention
18 juillet 2007

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..?)

je vais me renseigner sur le PIT..
merci de vos réponse :)
Messages postés
1100
Date d'inscription
jeudi 24 avril 2003
Statut
Membre
Dernière intervention
17 octobre 2012
7
Bonjour,

C'est quoi l'intérêt d"une opération toute les millisecondes ?

Merci et bonne prog,
@++

Le créateur du site http://victorlogiciels.com
Messages postés
6
Date d'inscription
samedi 25 mars 2006
Statut
Membre
Dernière intervention
18 juillet 2007

Oupss problème avant le post précedent.. (on peut pas éditer un post?? si un modo passe par ici, il peut supprimer le message d'avant qui copie-colle mon premier message)

Bon je recommence :

Mon problème n'est pas d'atteindre la milliseconde, ca j'y arrive. Le soucis c'est d'assurer un taux d'erreur minimum. Par taux d'erreur, comprendre timeout trop long.

J'ai bidouillé un peu ma fonction pour integrer le current_time et gagner du temps d'execution...bref
J'ai fait des essais et j'arrive à un taux de timeout > 1.01ms (pour 1ms demandée) qui tourne autour de 1%. ( PC = Windows XP, P4@2GHz, 512Mo)
C'est un taux assez faible, mais mon application a des besoins assez stricts, spécialement, il faut éviter les grosses erreurs, puisque 0,1% des timeout dépassent les 2ms et certains vont jusqu'a atteindre 60ms!
Et comme mon appli fait tourner des milliers de ces timeout..ca arrive forcément un moment ou un autre.

Je vais me renseigner sur PIT.
Je crois malheureusement que je pourrais pas faire grand chose de plus sur windows facilement. (et je suis contraint à utiliser windows..)
en tout cas merci de vos réponses.
Messages postés
6
Date d'inscription
samedi 25 mars 2006
Statut
Membre
Dernière intervention
18 juillet 2007

Oupss problème avant le post précedent.. (on peut pas éditer un post?? si un modo passe par ici, il peut supprimer le message d'avant qui copie-colle mon premier message)

Bon je recommence :

Mon problème n'est pas d'atteindre la milliseconde, ca j'y arrive. Le soucis c'est d'assurer un taux d'erreur minimum. Par taux d'erreur, comprendre timeout trop long.

J'ai bidouillé un peu ma fonction pour integrer le current_time et gagner du temps d'execution...bref
J'ai fait des essais et j'arrive à un taux de timeout > 1.01ms (pour 1ms demandée) qui tourne autour de 1%. ( PC = Windows XP, P4@2GHz, 512Mo)
C'est un taux assez faible, mais mon application a des besoins assez stricts, spécialement, il faut éviter les grosses erreurs, puisque 0,1% des timeout dépassent les 2ms et certains vont jusqu'a atteindre 60ms!
Et comme mon appli fait tourner des milliers de ces timeout..ca arrive forcément un moment ou un autre.

Je vais me renseigner sur PIT.
Je crois malheureusement que je pourrais pas faire grand chose de plus sur windows facilement. (et je suis contraint à utiliser windows..)
en tout cas merci de vos réponses.
Messages postés
1100
Date d'inscription
jeudi 24 avril 2003
Statut
Membre
Dernière intervention
17 octobre 2012
7
Bonjour,

Tu ne me dis toujours pas à quoi va te servir la régularité.

Si c'est qu'une histoire de décallage de temps calcule l'action de ton programme en fonction de l'horloge système.

Merci et bonne prog,
@++

Le créateur du site http://victorlogiciels.com
Messages postés
6
Date d'inscription
samedi 25 mars 2006
Statut
Membre
Dernière intervention
18 juillet 2007

Il n'y pas d'interet à une opération toute les millisecondes (dans mon cas).
J'ai besoin de creer une pause de 1,2 ou 5ms pour mon appli, afin de simuler le temps d'une transmission. La pause ne me sert pas à générer une boucle régulière.
Messages postés
1100
Date d'inscription
jeudi 24 avril 2003
Statut
Membre
Dernière intervention
17 octobre 2012
7
Bonjour,

Tu simules quoi ?
Un navigateur lent ?

Merci et bonne prog,
@++

Le créateur du site http://victorlogiciels.com
Messages postés
6
Date d'inscription
samedi 25 mars 2006
Statut
Membre
Dernière intervention
18 juillet 2007

(re) Bonjour,

Je simule une liaison radio. Il faut donc modéliser l'envoi de paquet, qui est nettement plus lent qu'en local, ethernet ou même passage de paramètre intra-applicatifs.
Je vais essayer de compenser les timeout erronés ainsi que le temps de traitement de mon appli en faisant non pas des temps de pause fixes mais basé sur une sorte d'horloge qui sera incrémenté mathématiquement et sur laquelle devra se baser mon appli pour "s'arreter" (en fait, il ne s'arrete plus, mais il boucle sur la récupération du current_time..pas top niveau utilisation processus, mais ca gene pas tant que ca au final)

Merci.
A++.
Messages postés
1100
Date d'inscription
jeudi 24 avril 2003
Statut
Membre
Dernière intervention
17 octobre 2012
7
Bonjour,

Tu peux essayer de faire une fenêtre et un SetTimer qui est assez régulier.

Merci et bonne prog,
@++

Le créateur du site http://victorlogiciels.com
Messages postés
21041
Date d'inscription
jeudi 23 janvier 2003
Statut
Modérateur
Dernière intervention
21 août 2019
29
Surtout pas de timer, c'est quasi pire que Sleep().

Faudrait dédier un PC à ce processus. A cet effet, désactiver presque tous les services et tu fais une boucle perpétuelle dans un thread. Avant la boucle tu calcules combien de ticks il faut pour faire ta ms et dedans te suffit de l'appeler.
Modéle ici, tu verras si convient:
http://www.asmfr.com/code.aspx?id=23802

ciao...
BruNews, MVP VC++