C ++ в Linux: в каком контексте разветвленной задачи должен выполняться обратный вызов таймера? - PullRequest
2 голосов
/ 29 марта 2012

Я реализовал свои собственные классы Timer / Callback в C / C ++ в Linux, где процесс, требующий таймера для запуска либо ONE_SHOT, либо PERIODIC, создает экземпляр таймера, создает экземпляр объекта обратного вызова и связывает обратный вызов с ранее созданным объектом Timer. Класс Callback реализует метод triggered (), и когда таймер срабатывает в назначенное время ожидания, выполняется метод triggered (). (Ничего нового с точки зрения функциональности.) Мой класс Timer работает так: я поддерживаю минимальную кучу объектов Timer и, таким образом, всегда знаю, какой таймер будет срабатывать следующим. Существует задача таймера (TimerTask), которая сама по себе работает как отдельный процесс (созданный с помощью fork ()) и разделяет пулы памяти, из которых создаются объекты Timer и объекты Callback. TimerTask имеет основной цикл while (1), который продолжает проверять, имеет ли корень minheap объекта Timer время с начала эпохи, то есть LEQ, текущее время с начала эпохи. Если это так, таймер в корневом каталоге «сработал».

В настоящее время, когда срабатывает таймер, обратный вызов выполняется в контексте процесса TimerTask. В настоящее время я изменяю это поведение для запуска обработки обратного вызова для других задач (отправьте им информацию о том, что объект Timer запущен через очередь сообщений POSIX. Например, отправьте сообщение процессу создания объекта Timer), но мой вопрос к SO какие принципы стоят за этим? Выполнение обратного вызова в контексте TimerTask кажется плохой идеей, если я ожидаю обслуживания большого количества таймеров. Кажется хорошей идеей передать обработку обратного вызова другим процессам.

Каковы общие практические правила обработки обратного вызова в одной задаче / процессе над другой? Мое намерение состоит в том, чтобы обработать обратный вызов в получающей задаче, используя pthread, например:

void threadFunctionForTimerCallback (void* arg)
{
    while (1)
    {
      if ((mq_receive (msg_fd, buffer, attr.mq_msgsize, NULL)) == -1)
    exit (-1);
      else
    printf ("Message received %s\n", buffer);
    }
}

Будет ли это разумным решением? Но не берите в голову фактический способ получения сообщения от TimerTask (потоки или любой другой метод, не имеет значения), любые обсуждения и понимание проблемы назначения задачи для обратного вызова приветствуются.

1 Ответ

0 голосов
/ 29 марта 2012

Нет необходимости в занятом вращении while(1) для реализации таймера.Одним из традиционных и надежных способов реализации таймеров является использование minheap, поскольку вы организуете время истечения, а затем передаете время до истечения следующего таймера в качестве аргумента времени ожидания на select() или epoll().Используя select() вызов потока может одновременно отслеживать готовность файлового дескриптора, сигналы и таймеры.

Последние ядра поддерживают timerfd, который доставляет события истечения таймера в виде готовности файлового дескрипторадля чтения, которое снова может быть обработано с помощью select()/epoll().Это устраняет необходимость поддерживать minheap, однако требует системного вызова для каждого добавления / изменения / удаления таймера.

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

В любом случае, можно использовать доменные сокеты Unix для отправки сообщений туда и обратно между взаимодействующими процессами на одном хосте.Опять же, select()/epoll() ваши лучшие друзья.Или для передачи сообщений может использоваться более высокоуровневая инфраструктура, например 0MQ .

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