2009-02-02 8 views
2

J'ai besoin d'une minuterie pour exécuter des rappels avec une résolution relativement faible. Quelle est la meilleure façon d'implémenter une telle classe de minuteur C++ sous Linux? Y a-t-il des bibliothèques que je pourrais utiliser?classe de minuterie dans linux

+0

Qu'est-ce qu'une résolution relativement faible? – Loki

+0

haha, Loki. exactement ce que je pensais quand je lisais sa question –

+0

des centaines de millisecondes à secondes – jackhab

Répondre

14

Si vous écrivez dans un cadre (Glib, Qt, Wx, ...), vous aurez déjà une boucle d'événement avec des fonctionnalités de rappel chronométré. Je suppose que ce n'est pas le cas.

Si vous écrivez votre propre boucle d'événement, vous pouvez utiliser le gettimeofday/select paire (struct timeval, précision microseconde) ou la clock_gettime/nanosleep paire (struct timespec, précision nanoseconde) pour votre propre diffuseur d'événements. Même si cette dernière est à plus haute résolution, l'ordonnancement n'est jamais aussi précis, alors prenez tout ce qui vous convient le mieux.

#include <algorithm> 
#include <functional> 
#include <vector> 

#include <errno.h> 
#include <sys/time.h> 
#include <unistd.h> 

using namespace std; 

class scheduler { 
public: 
    scheduler(); 
    int events(); 
    void addEvent(const struct timeval, int (*)(void *), void *); 
    int dispatchUntil(const struct timeval &); 
    bool waitUntil(const struct timeval * = NULL); 
    int loopUntil(const struct timeval * = NULL); 

private: 
    static bool tv_le(const struct timeval &, const struct timeval &); 
    struct event { 
     struct timeval when; 
     int (*callback)(void *); 
     void *data; 
    }; 
    static struct _cmp 
     : public binary_function<bool, const struct event &, const struct event &> 
    { 
     bool operator()(const struct event &a, const struct event &b) { 
      return !tv_le(a.when, b.when); 
     } 
    } cmp; 
    vector<struct event> heap; 
}; 

bool scheduler::tv_le(const struct timeval &a, const struct timeval &b) { 
    return a.tv_sec < b.tv_sec || 
     a.tv_sec == b.tv_sec && a.tv_usec <= b.tv_usec; 
} 

scheduler::scheduler() : heap() {} 

int scheduler::events() { 
    return heap.size(); 
} 

void scheduler::addEvent(const struct timeval when, int (*callback)(void *), void *data) { 
    struct event ev = {when, callback, data}; 
    heap.push_back(ev); 
    push_heap(heap.begin(), heap.end(), cmp); 
} 

int scheduler::dispatchUntil(const struct timeval &tv) { 
    int count = 0; 
    while (heap.size() > 0 && tv_le(heap.front().when, tv)) { 
     struct event ev = heap.front(); 
     pop_heap(heap.begin(), heap.end(), cmp); 
     heap.pop_back(); 
     ev.callback(ev.data); 
     count++; 
    } 
    return count; 
} 

bool scheduler::waitUntil(const struct timeval *tv) { 
    if (heap.size() > 0 && (!tv || tv_le(heap.front().when, *tv))) 
     tv = &heap.front().when; 
    if (!tv) 
     return false; 
    struct timeval tv2; 
    do { 
     gettimeofday(&tv2, NULL); 
     if (tv_le(*tv, tv2)) 
      break; 
     tv2.tv_sec -= tv->tv_sec; 
     if ((tv2.tv_usec -= tv->tv_usec) < 0) { 
      tv2.tv_sec--; 
      tv2.tv_usec += 1000000; 
     } 
    } while (select(0, NULL, NULL, NULL, &tv2) < 0 && errno == EINTR); 
    return heap.size() > 0 && tv_le(*tv, heap.front().when); 
} 

int scheduler::loopUntil(const struct timeval *tv) { 
    int counter = 0; 
    while (waitUntil(tv)) 
     counter += dispatchUntil(heap.front().when); 
    return counter; 
} 

Avertissement: J'aime C. Je n'écris jamais en C++. Je fais juste semblant de connaître la langue.

Avertissement: écrit tout à l'heure et totalement non testé. L'idée de base est de garder les événements dans une file d'attente prioritaire, d'attendre le premier, de l'exécuter et de répéter.

+3

+1 pour le prétendant C++ – jacknad

0

Essayez la fonction clock_gettime(), défini dans time.h:

int clock_gettime(clockid_t clk_id, struct timespec *tp); 

struct timespec { 
    time_t tv_sec;  /* seconds */ 
    long  tv_nsec;  /* nanoseconds */ 
}; 

En général, vous pourrait l'appeler comme ceci:

struct timespec ts; 
clock_gettime(CLOCK_REALTIME, &ts); 
+1

Désolé, mais je voulais dire une minuterie où l'on peut enregistrer les rappels à lancer après un intervalle spécifié. – jackhab

0

Le struct timeval de l'en-tête de time.h est ce que vous recherchez. Il a le temps en secondes et en nanosecondes. Donc le temps total en nanosecondes est timeval.tv_sec * 1000000 + timeval.tv_usec. Assez facile, je pense.

#include <time.h> 
timeval theStartTime; 
gettimeofday(&theStartTime); 
std::cout<<"The time we got's seconds field = "<<theStartTime.tv_sec<<std::endl; 
std::cout<<"The time we got's nanoseconds field = "<<theStartTime.tv_usec<<std::endl; 
+1

Désolé, mais je voulais dire une minuterie où l'on peut enregistrer les rappels à lancer après un intervalle spécifié. – jackhab

0

Voici un lien pour une classe de minuterie. Vous n'aurez besoin que de créer la minuterie et de la transmettre pour le rechargement automatique ou non. un pointeur sur la fonction de rappel. et soit si vous voulez qu'il soit géré par un fil ou avec un signal. Si vous choisissez le signal, vous devez également passer le signo.

http://timerlinux.codeplex.com/

Si tu veux étudier plus sur minuterie ou signaux il y a un bon livre appelé programmation système Linux. Vous n'aurez qu'à lire 3 chapitres et expliquer tout cela.

Questions connexes