Je développe le serveur de jeu, qui est écrit en C. Et j'ai besoin de développer un cycle avec une certaine fréquence (50 fois par seconde) pour exécuter un algorithme. Le problème est que je ne peux pas suspendre le programme pendant un intervalle de temps exact - 20000 microsecondes. La fonction usleep(20000)
exécute environ 30000 microsecondes. Le résultat est toujours plus sur 10000 microsecondes que prévu.
Voici mon exemple simple de code:
#include <stdio.h>
#include <time.h>
#include <unistd.h>
int main( int argc, char ** argv )
{
const unsigned long long nano = 1000000000;
unsigned long long t1, t2;
struct timespec tm;
for(;;)
{
clock_gettime( CLOCK_REALTIME, &tm );
t1 = tm.tv_nsec + tm.tv_sec * nano;
usleep( 20000 );
clock_gettime( CLOCK_REALTIME, &tm );
t2 = tm.tv_nsec + tm.tv_sec * nano;
printf( "delay: %ld\n", ( t2 - t1 ) / 1000 );
}
return 0;
}
Et le résultat de son fonctionnement:
$ ./a.out
delay: 29233
delay: 29575
delay: 29621
delay: 29694
delay: 29688
delay: 29732
delay: 29709
delay: 29706
delay: 29666
delay: 29702
delay: 29702
delay: 29705
delay: 29789
delay: 29619
delay: 29785
delay: 29634
delay: 29692
delay: 29708
delay: 29701
delay: 29703
J'ai également essayé d'utiliser la fonction select()
, mais le résultat est le même qu'avec la sleep()
.
Expliquez-moi, s'il vous plaît, ce qui ne va pas avec mon code.
p.s .:
$ uname -a
FreeBSD home.com 9.0-RELEASE FreeBSD 9.0-RELEASE #0: Tue Jan 3 07:46:30 UTC 2012 [email protected]:/usr/obj/usr/src/sys/GENERIC AMD64
Au lieu de dormir pendant 20000 secondes, dormez pendant le temps restant jusqu'à ce que vous souhaitiez recommencer, en fonction de l'appel à clock_gettime
C'est à dire:
usleep( lasttime+20000-now ); // But make sure you don't sleep when the result is negative
Ce n'est pas que votre code a un problème, mais l'appel réel à dormir, lire l'heure, etc. prend du temps, et le système ne peut pas dormir pour l'heure exacte de toute façon à moins qu'il ne soit un multiple de son cycle d'horloge exact
Les fonctions de sommeil sur les systèmes non temps réel ne sont pas garanties de dormir la période exacte spécifiée; sur un système occupé, le processus ne sera réveillé que lorsque sa tranche de temps commencera. Ou, comme le dit la page de manuel , "l'activité du système peut allonger le sommeil d'une durée indéterminée".
La quantité proche de 10 ms sonne comme le kern.hz
la fréquence est réduite à 100, comme certains le recommandent pour VM .
La solution de contournement classique pour ce problème est celle proposée par Ofir: au lieu de spécifier un intervalle de sommeil fixe, spécifiez le temps restant pour dormir. En moyenne, votre boucle s'exécutera toutes les 20 ms, ce que vous souhaitez très probablement réaliser.