timer class in linux

后端 未结 5 1584
清歌不尽
清歌不尽 2021-02-04 22:27

I need a timer to execute callbacks with relatively low resolution. What\'s the best way to implement such C++ timer class in Linux? Are there any libraries I could use?

5条回答
  •  臣服心动
    2021-02-04 22:59

    If you're writing within a framework (Glib, Qt, Wx, ...), you'll already have an event loop with timed callback functionalities. I'll assume that's not the case.

    If you're writing your own event loop, you can use the gettimeofday/select pair (struct timeval, microsecond precision) or the clock_gettime/nanosleep pair (struct timespec, nanosecond precision) for your own event dispatcher. Even though latter interface is higher resolution, scheduling is never that accurate anyways, so take whatever fits best.

    #include 
    #include 
    #include 
    
    #include 
    #include 
    #include 
    
    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 operator()(const struct event &a, const struct event &b) {
                return !tv_le(a.when, b.when);
            }
        } cmp;
        vector 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;
    }
    

    Warning: I love C. I never write C++. I'm just pretending to know the language.

    Disclaimer: written just now and totally untested. The basic idea is to keep events in a priority queue, wait until the first one, run it, and repeat.

提交回复
热议问题