comment dormir avec précision dans une boucle while en C (Linux)?

Dans un code C (Linux OS), je dois dormir avec précision dans une boucle while, par exemple 10 000 microsecondes pour 1 000 fois. J’ai essayé usleep, nanosleep, select, pselect et d’autres méthodes sans succès. Une fois sur 50 fois, il dormait 100% plus longtemps (environ 20 000 USD). Je dois effectuer une action après chaque délai. Donc, chaque retard doit être très précis. Existe-t-il un moyen de dormir correctement dans ce cas? Merci..

MODIFIER:

#include  #include  int main(int argc, char *argv[]) { struct timespec t0, t1; long err; int i = 0; while (i < 1000) { clock_gettime(CLOCK_MONOTONIC, &t0); usleep(10000); clock_gettime(CLOCK_MONOTONIC, &t1); err = (long) ((t1.tv_sec - t0.tv_sec) * 1e6 + (t1.tv_nsec - t0.tv_nsec) / 1000) - 10000; printf("i = %d err = %ld\n", i, err); i++; } return 0; } 

RÉSULTAT (fichier_journal):

i = 0 err = -146
i = 1 err = -207
i = 2 err = -8
i = 3 err = -4
i = 4 err = -22
i = 5 err = 31
i = 6 err = -45
i = 7 err = 9
i = 8 err = 61
i = 9 err = -71
i = 10 err = -24
i = 11 err = 14
i = 12 err = -12
i = 13 err = -32
i = 14 err = -15
i = 15 err = 42
i = 16 err = -51
i = 17 err = -19
i = 18 err = -12
i = 19 err = 4
i = 20 err = 12
i = 21 err = -36
i = 22 err = -38
i = 23 err = 18
i = 24 err = 1
i = 25 err = -21
i = 26 err = -37
i = 27 err = 31
i = 28 err = -4
i = 29 err = -45
i = 30 err = -37
i = 31 err = 20
i = 32 err = -10
i = 33 err = -5
i = 34 err = -12
i = 35 err = -5
i = 36 err = -10
i = 37 err = -12
i = 38 err = -2
i = 39 err = 14
i = 40 err = -34
i = 41 err = -10
i = 42 err = -6
i = 43 err = 15
i = 44 err = -34
i = 45 err = -12
i = 46 err = -15
i = 47 err = -25
i = 48 err = 11614
i = 49 err = 2340
i = 50 err = 589
i = 51 err = 12254
i = 52 err = -93
i = 53 err = -19

Veillez pendant un court laps de temps, puis interrogez un compteur de haute fréquence pour compléter le délai. Basez tous les retards sur une lecture originale du compteur pour éviter toute dérive dans le temps. Par exemple, previous_count = counter (), wait_count = previous_count + delay_count, délai jusqu’au compteur () – wait_count> = 0, previous_count + = delay_count, …. Si la fréquence souhaitée n’est pas un multiple exact de la fréquence counter (), utilisez une variable pour la partie décimale du retard (j’appelle ce nombre-restant).

Puisque vous avez mentionné Windows, voici un exemple de thread exécuté à une fréquence fixe et compatible avec Windows XP, où une veille (1) peut prendre jusqu’à 2 ms. dwLateStep est une aide au débogage, incrémentée à chaque fois qu’un cycle prend trop de temps (il rattrapera si possible). Les délais sont basés sur une lecture originale du compteur (en utilisant uWait, uRem, uPrev, uDelta), il n’y a donc pas de dérive sur une longue période. C’est essentiellement ainsi que les jeux implémentent un fil de physique à fréquence fixe. Notez que .net framework n’est pas utilisé pour ce type de jeux car il met en pause un processus par intermittence afin de remballer la mémoire paginée. De tels jeux définiront la priorité des threads physiques au-dessus de la normale afin d’empêcher d’autres threads ou processus de l’interférer.

 typedef unsigned long long UI64; /* unsigned 64 bit int */ #define FREQ 400 /* frequency */ DWORD dwLateStep; /* late step count */ LARGE_INTEGER liPerfFreq; /* 64 bit frequency */ LARGE_INTEGER liPerfTemp; /* used for query */ UI64 uFreq = FREQ; /* process frequency */ UI64 uOrig; /* original tick */ UI64 uWait; /* tick rate / freq */ UI64 uRem = 0; /* tick rate % freq */ UI64 uPrev; /* previous tick based on original tick */ UI64 uDelta; /* current tick - previous */ UI64 u2ms; /* 2ms of ticks */ UI64 i; /* ... */ /* wait for some event to start thread */ QueryPerformanceFrequency(&liPerfFreq); u2ms = ((UI64)(liPerfFreq.QuadPart)+499) / ((UI64)500); timeBeginPeriod(1); /* set period to 1ms */ Sleep(128); /* wait for it to stabilize */ QueryPerformanceCounter((PLARGE_INTEGER)&liPerfTemp); uOrig = uPrev = liPerfTemp.QuadPart; for(i = 0; i < (uFreq*30); i++){ /* update uWait and uRem based on uRem */ uWait = ((UI64)(liPerfFreq.QuadPart) + uRem) / uFreq; uRem = ((UI64)(liPerfFreq.QuadPart) + uRem) % uFreq; /* wait for uWait ticks */ while(1){ QueryPerformanceCounter((PLARGE_INTEGER)&liPerfTemp); uDelta = (UI64)(liPerfTemp.QuadPart - uPrev); if(uDelta >= uWait) break; if((uWait - uDelta) > u2ms) Sleep(1); } if(uDelta >= (uWait*2)) dwLateStep += 1; uPrev += uWait; /* fixed frequency code goes here */ /* along with some type of break when done */ /* otherwise, this example runs for 30 seconds */ } timeEndPeriod(1); /* restore period */