tags:

views:

2628

answers:

5

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?

A: 

Try the clock_gettime() function, defined in time.h:

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

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

Typically you might call it like this:

struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
John Snelson
Sorry, but I meant a timer where one can register callbacks to be launched after a specified interval.
Jack
+4  A: 

Use the boost::asio library. It has both synchronous and asynchronous timers which call a callback.

http://www.boost.org/doc/libs/1_37_0/doc/html/boost_asio/tutorial.html

Jeffrey Martinez
A: 

The timeval struct from the time.h header is what you are looking for. It has time in seconds and nanoseconds. So total time in nanoseconds is timeval.tv_sec * 1000000 + timeval.tv_usec. Easy enough, I think.

#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;
windfinder
Sorry, but I meant a timer where one can register callbacks to be launched after a specified interval.
Jack
+4  A: 

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 <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;
}

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.

ephemient
A: 

here is a link for a timer class. u will only need to create timer and pass it value for auto reload or not. a pointer to call back function. and either if u want it to be handled by a thread or with signal. if u choose signal then u have to pass the signo also.

http://timerlinux.codeplex.com/

If u want to study more about timer or signals there is a good book called linux system programming. u will only have to read 3 chapters and its explaining it all.