2012-10-17 2 views
0

Récemment, j'ai essayé de créer une fonction d'attente qui attend 25 ms en utilisant l'horloge murale comme référence. J'ai regardé autour de moi et j'ai trouvé "gettimeofday", mais j'ai eu des problèmes avec ça. Mon code (simplifié):gettimeofday sur uLinux wierd behavior

while(1) 
{ 
    timeval start, end; 
    double t_us; 
    bool release = false;  
    while (release == false) 
    { 
     gettimeofday(&start, NULL); 

     DoStuff(); 

     { 
      gettimeofday(&end, NULL); 
      t_us = ((end.tv_sec - start.tv_sec) * 1000*1000) + (end.tv_usec - start.tv_usec); 

      if (t_us >= 25000) //25 ms 
      { 
       release = true; 
      } 
     } 
    } 
} 

Ce code fonctionne dans un thread (Posix), et il est lui-même, fonctionne très bien. DoStuff() est appelé toutes les 25ms. Il mange cependant tout le CPU s'il le peut (comme vous pouvez vous y attendre) alors évidemment ce n'est pas une bonne idée.

Lorsque j'ai essayé de l'étrangler en ajoutant un Sleep (1); dans la boucle d'attente après l'instruction if, la chose entière ralentit d'environ 50% (c'est-à-dire qu'elle s'appelle DoStuff toutes les 37 ms environ) Cela n'a aucun sens - en supposant que DoStuff et tous les autres threads terminent leurs tâches en dessous. 1) ms le taux de DoStuff appelé ne doit pas être affecté (permettant une marge d'erreur 1ms)

Je dors aussi essayé (0), usleep (1000) et usleep (0) mais le comportement est le même.

le même comportement se produit chaque fois un autre thread de priorité plus élevée a besoin de temps CPU (sans le sommeil). Il est comme si l'horloge cesse de compter lorsque le fil

runtime reliqnuishes. Je suis conscient que gettimeofday est vulnérable à des choses comme NTP updat es etc ... donc j'ai essayé d'utiliser clock_gettime mais relier -ltr sur mon système provoque des problèmes donc je ne pense pas que ce soit une option.

Est-ce que quelqu'un sait ce que je fais mal?

+0

Le code de la question est-il correct? Le 'while (release == false)' semble mal placé. –

+0

Une façon courante de dormir un peu sur les plateformes POSIX est d'utiliser la fonction ['select'] (http://linux.die.net/man/2/select). Aussi, si votre compilateur le supporte vous avez aussi ['std :: this_thread :: sleep_for'] (http://en.cppreference.com/w/cpp/thread/sleep_for). –

+0

@Joachim Oui, j'ai oublié les parantheses de boucle while - corrigé. – Lordmonkey

Répondre

2

La partie qui manque ici est la façon dont le noyau planifie les threads en fonction des tranches de temps. En chiffres bruts, si vous dormez au début de votre tranche de temps 1ms et que la programmation est effectuée sur une fréquence de 35ms, votre thread peut ne pas s'exécuter à nouveau pendant 35ms. Si vous dormez pendant 40ms, votre thread peut ne pas s'exécuter à nouveau pendant 70ms. Vous ne pouvez pas vraiment changer cela sans changer la planification, mais ce n'est pas recommandé en raison des implications globales de performance du système. Vous pouvez utiliser une minuterie "haute résolution", mais souvent cela est mis en œuvre dans une boucle de gaspillage de cycle serré "alors que ce n'est pas encore le temps, mâcher CPU" donc ce n'est pas vraiment souhaitable non plus. Si vous utilisiez une horloge à haute résolution et que vous l'interrogiez souvent à l'intérieur de votre boucle DoStuff, vous pourriez éventuellement jouer quelques tours comme courir pendant 30ms, puis faire un sommeil (1) qui pourrait effectivement abandonner votre thread pour le reste de votre timelice (par exemple 5ms) pour laisser courir d'autres threads. Genre de multitâche coopératif/préemptif si vous voulez. Il est toujours possible que vous ne retourniez pas au travail pendant une longue période si ...

1

Toutes les variantes de sleep()/usleep() impliquent de fournir le processeur à d'autres tâches exécutables. Votre programme ne peut alors s'exécuter qu'après avoir été replanifié par le noyau, ce qui semble durer environ 37 ms dans votre cas.