способы реализации таймера в рабочем потоке в C - PullRequest
1 голос
/ 27 января 2011

У меня есть рабочий поток, который получает работу из трубы. Как то так

void *worker(void *param) {
  while (!work_done) {
    read(g_workfds[0], work, sizeof(work));
    do_work(work);
  }
}

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

void *worker(void *param) {
  prev_uptime = get_uptime();
  while (!work_done) {
    // set g_workfds[0] as non-block
    now_uptime = get_uptime();
    if (now_uptime - prev_uptime > 1) {
       do_book_keeping();
       prev_uptime = now_uptime;
    }
    n = poll(g_workfds[0], 1000); // Wait for 1 second else timeout
    if (n == 0) // timed out 
       continue;
    read(g_workfds[0], work, sizeof(work));
    do_work(work);   // This can take more than 1 second also
  }
}

Я использую системное время работы вместо системного времени, потому что системное время может изменяться во время работы этого потока. Мне было интересно, есть ли другой лучший способ сделать это. Я не хочу рассматривать использование другого потока. Использование alarm() не вариант, так как он уже используется другим потоком в том же процессе. Это внедряется в среде Linux.

Ответы [ 3 ]

3 голосов
/ 27 января 2011

Я согласен с большей частью того, что написал webbi в своем ответе.Но есть одна проблема с его предложением использовать время вместо времени работы.Если системное время обновляется «вперед», оно будет работать как положено.Но если системное время будет установлено, скажем, на 30 секунд, то бухгалтерский учет не будет выполняться в течение 30 секунд, поскольку (now_time - prev_time) будет отрицательным (если не используется тип без знака, в этом случае он все равно будет работать).

Альтернативой может быть использование clock_gettime () с CLOCK_MONOTONIC в качестве clockid (http://linux.die.net/man/2/clock_gettime).Немного грязно, если вам не нужны меньшие единицы времени, чем секунды.

Кроме того, добавить код для обнаружения обратного скачка часов тоже не сложно.

2 голосов
/ 27 января 2011

Я нашел лучший способ, но это специфично для Linux, используя timerfd_create () системный вызов.Он заботится о смене системного времени.Ниже приведен возможный код псевдо:

void *worker(void *param) {
  int timerfd = timerfd_create(CLOCK_MONOTONIC, 0);  // Monotonic doesn't get affected by system time change
  // set timerfd to non-block 
  timerfd_settime(timerfd, 1 second timer);     // timer starts 
  while (!work_done) {
    // set g_workfds[0] as non-block
    n = poll(g_workfds[0] and timerfd, 0); // poll on both pipe and timerfd and Wait indefinetly 
    if (timerfd is readable) 
       do_book_keeping();
    if (g_workfds[0] is readable) {
       read(g_workfds[0], work, sizeof(work));
       do_work(work);   // This can take more than 1 second also
    }
  }
}

Кажется чище и read() на timerfd возвращает дополнительное время, если do_work() занимает много времени, что весьма полезно, поскольку do_book_keeping() ожидает вызовакаждую секунду.

0 голосов
/ 27 января 2011

Я нашел некоторые странные вещи в вашем коде ...

poll () имеет 3 аргумента, вы передаете 2, второй аргумент - это число структур, которые вы передаете в массиве struct firstparam, третий param - это тайм-аут.

Ссылка: http://linux.die.net/man/2/poll

Кроме того, мне подходит этот обходной путь, конечно, он не самый лучший, но он работает без участия другого потокаили alarm () и т. д. Вы используете время, а не время работы, это может привести к одной ошибке, если системная дата изменится, но затем она продолжит работать, так как будет обновляться и будет продолжать ждать в течение 1 секунды, независимо от того, какое время.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...