класс таймера в linux - PullRequest
       11

класс таймера в linux

2 голосов
/ 02 февраля 2009

Мне нужен таймер для выполнения обратных вызовов с относительно низким разрешением. Какой лучший способ реализовать такой класс таймера C ++ в Linux? Есть ли библиотеки, которые я мог бы использовать?

Ответы [ 5 ]

14 голосов
/ 03 февраля 2009

Если вы пишете в рамках (Glib, Qt, Wx, ...), у вас уже будет цикл обработки событий с функциями обратного вызова по времени. Я предполагаю, что это не так.

Если вы пишете свой собственный цикл обработки событий, вы можете использовать пару gettimeofday / select (struct timeval, микросекундная точность) или пару clock_gettime / nanosleep (struct timespec, наносекундную точность) ) для вашего собственного диспетчера событий. Несмотря на то, что последний интерфейс имеет более высокое разрешение, в любом случае планирование никогда не бывает таким точным, поэтому выбирайте все, что подходит.

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

Предупреждение: я люблю C. Я никогда не пишу на C ++. Я просто притворяюсь, что знаю язык.

Отказ от ответственности: написано только сейчас и полностью не проверено. Основная идея состоит в том, чтобы сохранить события в приоритетной очереди, дождаться первой, запустить ее и повторить.

7 голосов
/ 02 февраля 2009

Используйте библиотеку boost :: asio. Он имеет как синхронные, так и асинхронные таймеры, которые вызывают обратный вызов.

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

0 голосов
/ 16 июня 2009

вот ссылка на класс таймера. Вам нужно будет только создать таймер и передать его значение для автоматической перезагрузки или нет. указатель на функцию обратного вызова. и либо, если вы хотите, чтобы он был обработан потоком или с сигналом. если вы выбираете сигнал, то вы также должны пройти знак.

http://timerlinux.codeplex.com/

Если вы хотите больше узнать о таймере или сигналах, есть хорошая книга под названием «Системное программирование в Linux». вам останется только прочитать 3 главы и все это объяснить.

0 голосов
/ 02 февраля 2009

Структура timeval из заголовка time.h - это то, что вы ищете. Время в секундах и наносекундах. Таким образом, общее время в наносекундах равно timeval.tv_sec * 1000000 + timeval.tv_usec. Думаю, достаточно просто.

#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;
0 голосов
/ 02 февраля 2009

Попробуйте функцию clock_gettime (), определенную в time.h:

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

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

Обычно вы можете назвать это так:

struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...